Browse Source

rename XMREngine as Yengine (still not all done), big mess source formating changes, move state files to proper folder, fix a source file locking on errors, more changes for cross platform including from Mike,... yes yes i know a messy commit

UbitUmarov 6 years ago
parent
commit
2129d941ac
55 changed files with 33579 additions and 29605 deletions
  1. 0 1559
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptBinOpStr.cs
  2. 0 6258
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs
  3. 0 2637
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCollector.cs
  4. 0 1677
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs
  5. 0 250
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptConsts.cs
  6. 0 666
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs
  7. 0 256
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjCode.cs
  8. 0 947
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs
  9. 0 1724
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs
  10. 0 819
      OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTypeCast.cs
  11. 0 269
      OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs
  12. 0 491
      OpenSim/Region/ScriptEngine/XMREngine/XMREngXmrTestLs.cs
  13. 0 2102
      OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs
  14. 0 2109
      OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs
  15. 0 76
      OpenSim/Region/ScriptEngine/XMREngine/XMRInstSorpra.cs
  16. 0 5476
      OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs
  17. 0 102
      OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs
  18. 0 196
      OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs
  19. 35 24
      OpenSim/Region/ScriptEngine/YEngine/MMRDelegateCommon.cs
  20. 37 36
      OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs
  21. 33 24
      OpenSim/Region/ScriptEngine/YEngine/MMRInternalFuncDict.cs
  22. 1569 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptBinOpStr.cs
  23. 7170 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs
  24. 3105 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs
  25. 1882 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs
  26. 77 98
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs
  27. 287 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptConsts.cs
  28. 41 39
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs
  29. 727 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptInlines.cs
  30. 29 24
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptMyILGen.cs
  31. 245 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptObjCode.cs
  32. 1040 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptObjWriter.cs
  33. 325 248
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptReduce.cs
  34. 2972 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptTokenize.cs
  35. 1012 0
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptTypeCast.cs
  36. 158 95
      OpenSim/Region/ScriptEngine/YEngine/MMRScriptVarDict.cs
  37. 223 161
      OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs
  38. 578 0
      OpenSim/Region/ScriptEngine/YEngine/XMREngXmrTestLs.cs
  39. 1901 0
      OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs
  40. 56 48
      OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs
  41. 101 73
      OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs
  42. 2348 0
      OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs
  43. 201 206
      OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs
  44. 54 148
      OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs
  45. 227 280
      OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs
  46. 31 43
      OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs
  47. 133 104
      OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs
  48. 44 38
      OpenSim/Region/ScriptEngine/YEngine/XMRInstQueue.cs
  49. 238 250
      OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs
  50. 6296 0
      OpenSim/Region/ScriptEngine/YEngine/XMRObjectTokens.cs
  51. 60 44
      OpenSim/Region/ScriptEngine/YEngine/XMRSDTypeClObj.cs
  52. 240 0
      OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs
  53. 97 0
      OpenSim/Region/ScriptEngine/YEngine/XMRScriptUThread.cs
  54. 5 6
      bin/OpenSim.ini.example
  55. 2 2
      prebuild.xml

+ 0 - 1559
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptBinOpStr.cs

@@ -1,1559 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-using System.Text.RegularExpressions;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine {
-
-    /**
-     * @brief This class is used to catalog the code emit routines based on a key string
-     *        The key string has the two types (eg, "integer", "rotation") and the operator (eg, "*", "!=")
-     */
-    public delegate void BinOpStrEmitBO (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result);
-    public class BinOpStr {
-        public static readonly Dictionary<string, BinOpStr> defined = DefineBinOps ();
-
-        public Type outtype;           // type of result of computation
-        public BinOpStrEmitBO emitBO;  // how to compute result
-        public bool rmwOK;             // is the <operator>= form valid?
-
-        public BinOpStr (Type outtype, BinOpStrEmitBO emitBO)
-        {
-            this.outtype = outtype;
-            this.emitBO  = emitBO;
-            this.rmwOK   = false;
-        }
-
-        public BinOpStr (Type outtype, BinOpStrEmitBO emitBO, bool rmwOK)
-        {
-            this.outtype = outtype;
-            this.emitBO  = emitBO;
-            this.rmwOK   = rmwOK;
-        }
-
-        private static TokenTypeBool   tokenTypeBool   = new TokenTypeBool   (null);
-        private static TokenTypeChar   tokenTypeChar   = new TokenTypeChar   (null);
-        private static TokenTypeFloat  tokenTypeFloat  = new TokenTypeFloat  (null);
-        private static TokenTypeInt    tokenTypeInt    = new TokenTypeInt    (null);
-        private static TokenTypeList   tokenTypeList   = new TokenTypeList   (null);
-        private static TokenTypeRot    tokenTypeRot    = new TokenTypeRot    (null);
-        private static TokenTypeStr    tokenTypeStr    = new TokenTypeStr    (null);
-        private static TokenTypeVec    tokenTypeVec    = new TokenTypeVec    (null);
-
-        private static MethodInfo stringAddStringMethInfo = ScriptCodeGen.GetStaticMethod (typeof (string), "Concat",  new Type[] { typeof (string), typeof (string) });
-        private static MethodInfo stringCmpStringMethInfo = ScriptCodeGen.GetStaticMethod (typeof (string), "Compare", new Type[] { typeof (string), typeof (string) });
-
-        private static MethodInfo infoMethListAddFloat = GetBinOpsMethod ("MethListAddFloat", new Type[] { typeof (LSL_List),     typeof (double)  });
-        private static MethodInfo infoMethListAddInt   = GetBinOpsMethod ("MethListAddInt",   new Type[] { typeof (LSL_List),     typeof (int)          });
-        private static MethodInfo infoMethListAddKey   = GetBinOpsMethod ("MethListAddKey",   new Type[] { typeof (LSL_List),     typeof (string)       });
-        private static MethodInfo infoMethListAddRot   = GetBinOpsMethod ("MethListAddRot",   new Type[] { typeof (LSL_List),     typeof (LSL_Rotation) });
-        private static MethodInfo infoMethListAddStr   = GetBinOpsMethod ("MethListAddStr",   new Type[] { typeof (LSL_List),     typeof (string)       });
-        private static MethodInfo infoMethListAddVec   = GetBinOpsMethod ("MethListAddVec",   new Type[] { typeof (LSL_List),     typeof (LSL_Vector)   });
-        private static MethodInfo infoMethListAddList  = GetBinOpsMethod ("MethListAddList",  new Type[] { typeof (LSL_List),     typeof (LSL_List)     });
-        private static MethodInfo infoMethFloatAddList = GetBinOpsMethod ("MethFloatAddList", new Type[] { typeof (double),  typeof (LSL_List)     });
-        private static MethodInfo infoMethIntAddList   = GetBinOpsMethod ("MethIntAddList",   new Type[] { typeof (int),          typeof (LSL_List)     });
-        private static MethodInfo infoMethKeyAddList   = GetBinOpsMethod ("MethKeyAddList",   new Type[] { typeof (string),       typeof (LSL_List)     });
-        private static MethodInfo infoMethRotAddList   = GetBinOpsMethod ("MethRotAddList",   new Type[] { typeof (LSL_Rotation), typeof (LSL_List)     });
-        private static MethodInfo infoMethStrAddList   = GetBinOpsMethod ("MethStrAddList",   new Type[] { typeof (string),       typeof (LSL_List)     });
-        private static MethodInfo infoMethVecAddList   = GetBinOpsMethod ("MethVecAddList",   new Type[] { typeof (LSL_Vector),   typeof (LSL_List)     });
-        private static MethodInfo infoMethListEqList   = GetBinOpsMethod ("MethListEqList",   new Type[] { typeof (LSL_List),     typeof (LSL_List)     });
-        private static MethodInfo infoMethListNeList   = GetBinOpsMethod ("MethListNeList",   new Type[] { typeof (LSL_List),     typeof (LSL_List)     });
-        private static MethodInfo infoMethRotEqRot     = GetBinOpsMethod ("MethRotEqRot",     new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethRotNeRot     = GetBinOpsMethod ("MethRotNeRot",     new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethRotAddRot    = GetBinOpsMethod ("MethRotAddRot",    new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethRotSubRot    = GetBinOpsMethod ("MethRotSubRot",    new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethRotMulRot    = GetBinOpsMethod ("MethRotMulRot",    new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethRotDivRot    = GetBinOpsMethod ("MethRotDivRot",    new Type[] { typeof (LSL_Rotation), typeof (LSL_Rotation) });
-        private static MethodInfo infoMethVecEqVec     = GetBinOpsMethod ("MethVecEqVec",     new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecNeVec     = GetBinOpsMethod ("MethVecNeVec",     new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecAddVec    = GetBinOpsMethod ("MethVecAddVec",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecSubVec    = GetBinOpsMethod ("MethVecSubVec",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecMulVec    = GetBinOpsMethod ("MethVecMulVec",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecModVec    = GetBinOpsMethod ("MethVecModVec",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecMulFloat  = GetBinOpsMethod ("MethVecMulFloat",  new Type[] { typeof (LSL_Vector),   typeof (double)  });
-        private static MethodInfo infoMethFloatMulVec  = GetBinOpsMethod ("MethFloatMulVec",  new Type[] { typeof (double),  typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecDivFloat  = GetBinOpsMethod ("MethVecDivFloat",  new Type[] { typeof (LSL_Vector),   typeof (double)  });
-        private static MethodInfo infoMethVecMulInt    = GetBinOpsMethod ("MethVecMulInt",    new Type[] { typeof (LSL_Vector),   typeof (int)          });
-        private static MethodInfo infoMethIntMulVec    = GetBinOpsMethod ("MethIntMulVec",    new Type[] { typeof (int),          typeof (LSL_Vector)   });
-        private static MethodInfo infoMethVecDivInt    = GetBinOpsMethod ("MethVecDivInt",    new Type[] { typeof (LSL_Vector),   typeof (int)          });
-        private static MethodInfo infoMethVecMulRot    = GetBinOpsMethod ("MethVecMulRot",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Rotation) });
-        private static MethodInfo infoMethVecDivRot    = GetBinOpsMethod ("MethVecDivRot",    new Type[] { typeof (LSL_Vector),   typeof (LSL_Rotation) });
-
-        private static MethodInfo GetBinOpsMethod (string name, Type[] types)
-        {
-            return ScriptCodeGen.GetStaticMethod (typeof (BinOpStr), name, types);
-        }
-
-        /**
-         * @brief Create a dictionary for processing binary operators.
-         *        This tells us, for a given type, an operator and another type,
-         *        is the operation permitted, and if so, what is the type of the result?
-         * The key is <lefttype><opcode><righttype>,
-         *   where <lefttype> and <righttype> are strings returned by (TokenType...).ToString()
-         *   and <opcode> is string returned by (TokenKw...).ToString()
-         * The value is a BinOpStr struct giving the resultant type and a method to generate the code.
-         */
-        private static Dictionary<string, BinOpStr> DefineBinOps ()
-        {
-            Dictionary<string, BinOpStr> bos = new Dictionary<string, BinOpStr> ();
-
-            string[] booltypes = new string[] { "bool", "char", "float", "integer", "key", "list", "string" };
-
-            /*
-             * Get the && and || all out of the way...
-             * Simply cast their left and right operands to boolean then process.
-             */
-            for (int i = 0; i < booltypes.Length; i ++) {
-                for (int j = 0; j < booltypes.Length; j ++) {
-                    bos.Add (booltypes[i] + "&&" + booltypes[j], 
-                             new BinOpStr (typeof (bool), BinOpStrAndAnd));
-                    bos.Add (booltypes[i] + "||" + booltypes[j], 
-                             new BinOpStr (typeof (bool), BinOpStrOrOr));
-                }
-            }
-
-            /*
-             * Pound through all the other combinations we support.
-             */
-
-            // boolean : somethingelse
-            DefineBinOpsBoolX (bos, "bool");
-            DefineBinOpsBoolX (bos, "char");
-            DefineBinOpsBoolX (bos, "float");
-            DefineBinOpsBoolX (bos, "integer");
-            DefineBinOpsBoolX (bos, "key");
-            DefineBinOpsBoolX (bos, "list");
-            DefineBinOpsBoolX (bos, "string");
-
-            // stuff with chars
-            DefineBinOpsChar (bos);
-
-            // somethingelse : boolean
-            DefineBinOpsXBool (bos, "char");
-            DefineBinOpsXBool (bos, "float");
-            DefineBinOpsXBool (bos, "integer");
-            DefineBinOpsXBool (bos, "key");
-            DefineBinOpsXBool (bos, "list");
-            DefineBinOpsXBool (bos, "string");
-
-            // float : somethingelse
-            DefineBinOpsFloatX (bos, "float");
-            DefineBinOpsFloatX (bos, "integer");
-
-            // integer : float
-            DefineBinOpsXFloat (bos, "integer");
-
-            // anything else with integers
-            DefineBinOpsInteger (bos);
-
-            // key : somethingelse
-            DefineBinOpsKeyX (bos, "key");
-            DefineBinOpsKeyX (bos, "string");
-
-            // string : key
-            DefineBinOpsXKey (bos, "string");
-
-            // things with lists
-            DefineBinOpsList (bos);
-
-            // things with rotations
-            DefineBinOpsRotation (bos);
-
-            // things with strings
-            DefineBinOpsString (bos);
-
-            // things with vectors
-            DefineBinOpsVector (bos);
-
-            // Contrary to some beliefs, scripts do things like string+integer and integer+string
-            bos.Add ("bool+string",    new BinOpStr (typeof (string), BinOpStrStrAddStr));
-            bos.Add ("char+string",    new BinOpStr (typeof (string), BinOpStrStrAddStr));
-            bos.Add ("float+string",   new BinOpStr (typeof (string), BinOpStrStrAddStr));
-            bos.Add ("integer+string", new BinOpStr (typeof (string), BinOpStrStrAddStr));
-            bos.Add ("string+bool",    new BinOpStr (typeof (string), BinOpStrStrAddStr, true));
-            bos.Add ("string+char",    new BinOpStr (typeof (string), BinOpStrStrAddStr, true));
-            bos.Add ("string+float",   new BinOpStr (typeof (string), BinOpStrStrAddStr, true));
-            bos.Add ("string+integer", new BinOpStr (typeof (string), BinOpStrStrAddStr, true));
-
-            // Now for our final slight-of-hand, we're going to scan through all those.
-            // And wherever we see an 'integer' in the key, we are going to make another
-            // entry with 'bool', as we want to accept a bool as having a value of 0 or 1.
-            // This lets us do things like 3.5 * (x > 0).
-
-            Dictionary<string, BinOpStr> bos2 = new Dictionary<string, BinOpStr> ();
-            foreach (KeyValuePair<string, BinOpStr> kvp in bos) {
-                string   key = kvp.Key;
-                BinOpStr val = kvp.Value;
-                bos2.Add (key, val);
-            }
-            Regex wordReg = new Regex("\\w+");
-            Regex opReg = new Regex("\\W+");
-            foreach (KeyValuePair<string, BinOpStr> kvp in bos) {
-                string   key  = kvp.Key;
-                BinOpStr val  = kvp.Value;
-                MatchCollection matches = wordReg.Matches(key);
-                if (matches.Count != 2)
-                    continue;
-                Match opM = opReg.Match(key);
-                if (!opM.Success)
-                    continue;
-                string left = matches[0].Value;
-                string right = matches[1].Value;
-                string op = opM.Value;
-                string key2;
-                if (left == "integer" && right == "integer")
-                {
-                    key2 = "bool"+op+"bool";
-                    if (!bos2.ContainsKey (key2)) bos2.Add (key2, val);
-                    key2 = "bool"+op+"integer";
-                    if (!bos2.ContainsKey (key2)) bos2.Add (key2, val);
-                    key2 = "integer"+op+"bool";
-                    if (!bos2.ContainsKey (key2)) bos2.Add (key2, val);
-                }
-                else
-                {
-                    key2 = key.Replace("integer", "bool");
-                    if (!bos2.ContainsKey (key2)) bos2.Add (key2, val);
-                }
-            }
-            return bos2;
-        }
-
-        private static void DefineBinOpsBoolX (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add ("bool|"  + x, new BinOpStr (typeof (int),  BinOpStrBoolOrX));
-            bos.Add ("bool^"  + x, new BinOpStr (typeof (int),  BinOpStrBoolXorX));
-            bos.Add ("bool&"  + x, new BinOpStr (typeof (int),  BinOpStrBoolAndX));
-            bos.Add ("bool==" + x, new BinOpStr (typeof (bool), BinOpStrBoolEqX));
-            bos.Add ("bool!=" + x, new BinOpStr (typeof (bool), BinOpStrBoolNeX));
-        }
-
-        private static void DefineBinOpsXBool (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add (x + "|bool",  new BinOpStr (typeof (int),  BinOpStrBoolOrX));
-            bos.Add (x + "^bool",  new BinOpStr (typeof (int),  BinOpStrBoolXorX));
-            bos.Add (x + "&bool",  new BinOpStr (typeof (int),  BinOpStrBoolAndX));
-            bos.Add (x + "==bool", new BinOpStr (typeof (bool), BinOpStrBoolEqX));
-            bos.Add (x + "!=bool", new BinOpStr (typeof (bool), BinOpStrBoolNeX));
-        }
-
-        private static void DefineBinOpsFloatX (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add ("float==" + x, new BinOpStr (typeof (bool),        BinOpStrFloatEqX));
-            bos.Add ("float!=" + x, new BinOpStr (typeof (bool),        BinOpStrFloatNeX));
-            bos.Add ("float<"  + x, new BinOpStr (typeof (bool),        BinOpStrFloatLtX));
-            bos.Add ("float<=" + x, new BinOpStr (typeof (bool),        BinOpStrFloatLeX));
-            bos.Add ("float>"  + x, new BinOpStr (typeof (bool),        BinOpStrFloatGtX));
-            bos.Add ("float>=" + x, new BinOpStr (typeof (bool),        BinOpStrFloatGeX));
-            bos.Add ("float+"  + x, new BinOpStr (typeof (double), BinOpStrFloatAddX, true));
-            bos.Add ("float-"  + x, new BinOpStr (typeof (double), BinOpStrFloatSubX, true));
-            bos.Add ("float*"  + x, new BinOpStr (typeof (double), BinOpStrFloatMulX, true));
-            bos.Add ("float/"  + x, new BinOpStr (typeof (double), BinOpStrFloatDivX, true));
-            bos.Add ("float%"  + x, new BinOpStr (typeof (double), BinOpStrFloatModX, true));
-        }
-
-        private static void DefineBinOpsXFloat (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add (x + "==float", new BinOpStr (typeof (bool),        BinOpStrXEqFloat));
-            bos.Add (x + "!=float", new BinOpStr (typeof (bool),        BinOpStrXNeFloat));
-            bos.Add (x + "<float",  new BinOpStr (typeof (bool),        BinOpStrXLtFloat));
-            bos.Add (x + "<=float", new BinOpStr (typeof (bool),        BinOpStrXLeFloat));
-            bos.Add (x + ">float",  new BinOpStr (typeof (bool),        BinOpStrXGtFloat));
-            bos.Add (x + ">=float", new BinOpStr (typeof (bool),        BinOpStrXGeFloat));
-            bos.Add (x + "+float",  new BinOpStr (typeof (double), BinOpStrXAddFloat, true));
-            bos.Add (x + "-float",  new BinOpStr (typeof (double), BinOpStrXSubFloat, true));
-            bos.Add (x + "*float",  new BinOpStr (typeof (double), BinOpStrXMulFloat, true));
-            bos.Add (x + "/float",  new BinOpStr (typeof (double), BinOpStrXDivFloat, true));
-            bos.Add (x + "%float",  new BinOpStr (typeof (double), BinOpStrXModFloat, true));
-        }
-
-        private static void DefineBinOpsChar (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("char==char",   new BinOpStr (typeof (bool), BinOpStrCharEqChar));
-            bos.Add ("char!=char",   new BinOpStr (typeof (bool), BinOpStrCharNeChar));
-            bos.Add ("char<char",    new BinOpStr (typeof (bool), BinOpStrCharLtChar));
-            bos.Add ("char<=char",   new BinOpStr (typeof (bool), BinOpStrCharLeChar));
-            bos.Add ("char>char",    new BinOpStr (typeof (bool), BinOpStrCharGtChar));
-            bos.Add ("char>=char",   new BinOpStr (typeof (bool), BinOpStrCharGeChar));
-            bos.Add ("char+integer", new BinOpStr (typeof (char), BinOpStrCharAddInt, true));
-            bos.Add ("char-integer", new BinOpStr (typeof (char), BinOpStrCharSubInt, true));
-            bos.Add ("char-char",    new BinOpStr (typeof (int),  BinOpStrCharSubChar));
-        }
-
-        private static void DefineBinOpsInteger (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("integer==integer", new BinOpStr (typeof (bool), BinOpStrIntEqInt));
-            bos.Add ("integer!=integer", new BinOpStr (typeof (bool), BinOpStrIntNeInt));
-            bos.Add ("integer<integer",  new BinOpStr (typeof (bool), BinOpStrIntLtInt));
-            bos.Add ("integer<=integer", new BinOpStr (typeof (bool), BinOpStrIntLeInt));
-            bos.Add ("integer>integer",  new BinOpStr (typeof (bool), BinOpStrIntGtInt));
-            bos.Add ("integer>=integer", new BinOpStr (typeof (bool), BinOpStrIntGeInt));
-            bos.Add ("integer|integer",  new BinOpStr (typeof (int),  BinOpStrIntOrInt,  true));
-            bos.Add ("integer^integer",  new BinOpStr (typeof (int),  BinOpStrIntXorInt, true));
-            bos.Add ("integer&integer",  new BinOpStr (typeof (int),  BinOpStrIntAndInt, true));
-            bos.Add ("integer+integer",  new BinOpStr (typeof (int),  BinOpStrIntAddInt, true));
-            bos.Add ("integer-integer",  new BinOpStr (typeof (int),  BinOpStrIntSubInt, true));
-            bos.Add ("integer*integer",  new BinOpStr (typeof (int),  BinOpStrIntMulInt, true));
-            bos.Add ("integer/integer",  new BinOpStr (typeof (int),  BinOpStrIntDivInt, true));
-            bos.Add ("integer%integer",  new BinOpStr (typeof (int),  BinOpStrIntModInt, true));
-            bos.Add ("integer<<integer", new BinOpStr (typeof (int),  BinOpStrIntShlInt, true));
-            bos.Add ("integer>>integer", new BinOpStr (typeof (int),  BinOpStrIntShrInt, true));
-        }
-
-        private static void DefineBinOpsKeyX (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add ("key==" + x, new BinOpStr (typeof (bool), BinOpStrKeyEqX));
-            bos.Add ("key!=" + x, new BinOpStr (typeof (bool), BinOpStrKeyNeX));
-        }
-
-        private static void DefineBinOpsXKey (Dictionary<string, BinOpStr> bos, string x)
-        {
-            bos.Add (x + "==key", new BinOpStr (typeof (bool), BinOpStrKeyEqX));
-            bos.Add (x + "!=key", new BinOpStr (typeof (bool), BinOpStrKeyNeX));
-        }
-
-        private static void DefineBinOpsList (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("list+float",     new BinOpStr (typeof (LSL_List), BinOpStrListAddFloat, true));
-            bos.Add ("list+integer",   new BinOpStr (typeof (LSL_List), BinOpStrListAddInt,   true));
-            bos.Add ("list+key",       new BinOpStr (typeof (LSL_List), BinOpStrListAddKey,   true));
-            bos.Add ("list+list",      new BinOpStr (typeof (LSL_List), BinOpStrListAddList,  true));
-            bos.Add ("list+rotation",  new BinOpStr (typeof (LSL_List), BinOpStrListAddRot,   true));
-            bos.Add ("list+string",    new BinOpStr (typeof (LSL_List), BinOpStrListAddStr,   true));
-            bos.Add ("list+vector",    new BinOpStr (typeof (LSL_List), BinOpStrListAddVec,   true));
-
-            bos.Add ("float+list",     new BinOpStr (typeof (LSL_List), BinOpStrFloatAddList));
-            bos.Add ("integer+list",   new BinOpStr (typeof (LSL_List), BinOpStrIntAddList));
-            bos.Add ("key+list",       new BinOpStr (typeof (LSL_List), BinOpStrKeyAddList));
-            bos.Add ("rotation+list",  new BinOpStr (typeof (LSL_List), BinOpStrRotAddList));
-            bos.Add ("string+list",    new BinOpStr (typeof (LSL_List), BinOpStrStrAddList));
-            bos.Add ("vector+list",    new BinOpStr (typeof (LSL_List), BinOpStrVecAddList));
-
-            bos.Add ("list==list",     new BinOpStr (typeof (bool), BinOpStrListEqList));
-            bos.Add ("list!=list",     new BinOpStr (typeof (int),  BinOpStrListNeList));
-        }
-
-        // all operations allowed by LSL_Rotation definition
-        private static void DefineBinOpsRotation (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("rotation==rotation", new BinOpStr (typeof (bool),         BinOpStrRotEqRot));
-            bos.Add ("rotation!=rotation", new BinOpStr (typeof (bool),         BinOpStrRotNeRot));
-            bos.Add ("rotation+rotation",  new BinOpStr (typeof (LSL_Rotation), BinOpStrRotAddRot, true));
-            bos.Add ("rotation-rotation",  new BinOpStr (typeof (LSL_Rotation), BinOpStrRotSubRot, true));
-            bos.Add ("rotation*rotation",  new BinOpStr (typeof (LSL_Rotation), BinOpStrRotMulRot, true));
-            bos.Add ("rotation/rotation",  new BinOpStr (typeof (LSL_Rotation), BinOpStrRotDivRot, true));
-        }
-
-        private static void DefineBinOpsString (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("string==string", new BinOpStr (typeof (bool),   BinOpStrStrEqStr));
-            bos.Add ("string!=string", new BinOpStr (typeof (bool),   BinOpStrStrNeStr));
-            bos.Add ("string<string",  new BinOpStr (typeof (bool),   BinOpStrStrLtStr));
-            bos.Add ("string<=string", new BinOpStr (typeof (bool),   BinOpStrStrLeStr));
-            bos.Add ("string>string",  new BinOpStr (typeof (bool),   BinOpStrStrGtStr));
-            bos.Add ("string>=string", new BinOpStr (typeof (bool),   BinOpStrStrGeStr));
-            bos.Add ("string+string",  new BinOpStr (typeof (string), BinOpStrStrAddStr, true));
-        }
-
-        // all operations allowed by LSL_Vector definition
-        private static void DefineBinOpsVector (Dictionary<string, BinOpStr> bos)
-        {
-            bos.Add ("vector==vector",  new BinOpStr (typeof (bool),        BinOpStrVecEqVec));
-            bos.Add ("vector!=vector",  new BinOpStr (typeof (bool),        BinOpStrVecNeVec));
-            bos.Add ("vector+vector",   new BinOpStr (typeof (LSL_Vector),  BinOpStrVecAddVec, true));
-            bos.Add ("vector-vector",   new BinOpStr (typeof (LSL_Vector),  BinOpStrVecSubVec, true));
-            bos.Add ("vector*vector",   new BinOpStr (typeof (double), BinOpStrVecMulVec));
-            bos.Add ("vector%vector",   new BinOpStr (typeof (LSL_Vector),  BinOpStrVecModVec, true));
-
-            bos.Add ("vector*float",    new BinOpStr (typeof (LSL_Vector),  BinOpStrVecMulFloat, true));
-            bos.Add ("float*vector",    new BinOpStr (typeof (LSL_Vector),  BinOpStrFloatMulVec));
-            bos.Add ("vector/float",    new BinOpStr (typeof (LSL_Vector),  BinOpStrVecDivFloat, true));
-
-            bos.Add ("vector*integer",  new BinOpStr (typeof (LSL_Vector),  BinOpStrVecMulInt, true));
-            bos.Add ("integer*vector",  new BinOpStr (typeof (LSL_Vector),  BinOpStrIntMulVec));
-            bos.Add ("vector/integer",  new BinOpStr (typeof (LSL_Vector),  BinOpStrVecDivInt, true));
-
-            bos.Add ("vector*rotation", new BinOpStr (typeof (LSL_Vector),  BinOpStrVecMulRot, true));
-            bos.Add ("vector/rotation", new BinOpStr (typeof (LSL_Vector),  BinOpStrVecDivRot, true));
-        }
-
-        /**
-         * @brief These methods actually emit the code to perform the arithmetic.
-         * @param scg    = what script we are compiling
-         * @param left   = left-hand operand location in memory (type as given by BinOpStr entry)
-         * @param right  = right-hand operand location in memory (type as given by BinOpStr entry)
-         * @param result = result location in memory (type as given by BinOpStr entry)
-         */
-        private static void BinOpStrAndAnd (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeBool);
-            right.PushVal (scg, errorAt, tokenTypeBool);
-            scg.ilGen.Emit (errorAt, OpCodes.And);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrOrOr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeBool);
-            right.PushVal (scg, errorAt, tokenTypeBool);
-            scg.ilGen.Emit (errorAt, OpCodes.Or);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrBoolOrX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Or);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrBoolXorX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrBoolAndX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.And);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrBoolEqX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeBool);
-            right.PushVal (scg, errorAt, tokenTypeBool);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrBoolNeX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeBool);
-            right.PushVal (scg, errorAt, tokenTypeBool);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatEqX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatNeX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatLtX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatLeX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatGtX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatGeX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrFloatAddX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Add);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrFloatSubX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Sub);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrFloatMulX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Mul);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrFloatDivX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Div);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrFloatModX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Rem);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrXEqFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXNeFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXLtFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXLeFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXGtFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXGeFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrXAddFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Add);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrXSubFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Sub);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrXMulFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Mul);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrXDivFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Div);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrXModFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Rem);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrCharEqChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharNeChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharLtChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharLeChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharGtChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharGeChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrCharAddInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Add);
-            result.PopPost (scg, errorAt, tokenTypeChar);
-        }
-
-        private static void BinOpStrCharSubInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Sub);
-            result.PopPost (scg, errorAt, tokenTypeChar);
-        }
-
-        private static void BinOpStrCharSubChar (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeChar);
-            right.PushVal (scg, errorAt, tokenTypeChar);
-            scg.ilGen.Emit (errorAt, OpCodes.Sub);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntEqInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntNeInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntLtInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntLeInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntGtInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntGeInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrIntOrInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Or);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntXorInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntAndInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.And);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntAddInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Add);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntSubInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Sub);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntMulInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Mul);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntDivInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            // note that we must allow 0x800000/-1 -> 0x80000000 for lslangtest1.lsl
-            // so sign-extend the operands to 64-bit then divide and truncate result
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I8);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I8);
-            scg.ilGen.Emit (errorAt, OpCodes.Div);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I4);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntModInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            // note that we must allow 0x800000%-1 -> 0 for lslangtest1.lsl
-            // so sign-extend the operands to 64-bit then mod and truncate result
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I8);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I8);
-            scg.ilGen.Emit (errorAt, OpCodes.Rem);
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I4);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntShlInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Shl);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrIntShrInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Shr);
-            result.PopPost (scg, errorAt, tokenTypeInt);
-        }
-
-        private static void BinOpStrKeyEqX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrKeyNeX (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrListAddFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddFloat);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddInt);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddKey (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddKey);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddRot);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddStr);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListAddVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListAddVec);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrFloatAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethFloatAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrIntAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethIntAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrKeyAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethKeyAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrRotAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrStrAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethStrAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrVecAddList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecAddList);
-            result.PopPost (scg, errorAt, tokenTypeList);
-        }
-
-        private static void BinOpStrListEqList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListEqList);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrListNeList (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeList);
-            right.PushVal (scg, errorAt, tokenTypeList);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethListNeList);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrRotEqRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotEqRot);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrRotNeRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotNeRot);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrRotAddRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotAddRot);
-            result.PopPost (scg, errorAt, tokenTypeRot);
-        }
-
-        private static void BinOpStrRotSubRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotSubRot);
-            result.PopPost (scg, errorAt, tokenTypeRot);
-        }
-
-        private static void BinOpStrRotMulRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotMulRot);
-            result.PopPost (scg, errorAt, tokenTypeRot);
-        }
-
-        private static void BinOpStrRotDivRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeRot);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethRotDivRot);
-            result.PopPost (scg, errorAt, tokenTypeRot);
-        }
-
-        private static void BinOpStrStrEqStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrStrNeStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrStrLtStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrStrLeStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Clt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrStrGtStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrStrGeStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringCmpStringMethInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_M1);
-            scg.ilGen.Emit (errorAt, OpCodes.Cgt);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        // Called by many type combinations so both operands need to be cast to strings
-        private static void BinOpStrStrAddStr (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeStr);
-            right.PushVal (scg, errorAt, tokenTypeStr);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringAddStringMethInfo);
-            result.PopPost (scg, errorAt, tokenTypeStr);
-        }
-
-        private static void BinOpStrVecEqVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecEqVec);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrVecNeVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecNeVec);
-            result.PopPost (scg, errorAt, tokenTypeBool);
-        }
-
-        private static void BinOpStrVecAddVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecAddVec);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecSubVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecSubVec);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecMulVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecMulVec);
-            result.PopPost (scg, errorAt, tokenTypeFloat);
-        }
-
-        private static void BinOpStrVecModVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecModVec);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecMulFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecMulFloat);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrFloatMulVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeFloat);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethFloatMulVec);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecDivFloat (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeFloat);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecDivFloat);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecMulInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecMulInt);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrIntMulVec (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeInt);
-            right.PushVal (scg, errorAt, tokenTypeVec);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethIntMulVec);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecDivInt (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeInt);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecDivInt);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecMulRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecMulRot);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        private static void BinOpStrVecDivRot (ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
-        {
-            result.PopPre (scg, errorAt);
-            left.PushVal (scg, errorAt, tokenTypeVec);
-            right.PushVal (scg, errorAt, tokenTypeRot);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, infoMethVecDivRot);
-            result.PopPost (scg, errorAt, tokenTypeVec);
-        }
-
-        /**
-         * @brief These methods are called at runtime as helpers.
-         *        Needed to pick up functionality defined by overloaded operators of LSL_ types.
-         *        They need to be marked public or runtime says they are inaccessible.
-         */
-        public static LSL_List MethListAddFloat (LSL_List left, double right)
-        {
-            return MethListAddObj (left, new LSL_Float (right));
-        }
-        public static LSL_List MethListAddInt (LSL_List left, int right)
-        {
-            return MethListAddObj (left, new LSL_Integer (right));
-        }
-        public static LSL_List MethListAddKey (LSL_List left, string right)
-        {
-            return MethListAddObj (left, new LSL_Key (right));
-        }
-        public static LSL_List MethListAddRot (LSL_List left, LSL_Rotation right)
-        {
-            return MethListAddObj (left, right);
-        }
-        public static LSL_List MethListAddStr (LSL_List left, string right)
-        {
-            return MethListAddObj (left, new LSL_String (right));
-        }
-        public static LSL_List MethListAddVec (LSL_List left, LSL_Vector right)
-        {
-            return MethListAddObj (left, right);
-        }
-        public static LSL_List MethListAddObj (LSL_List left, object right)
-        {
-            int oldlen = left.Length;
-            object[] newarr = new object[oldlen+1];
-            Array.Copy (left.Data, newarr, oldlen);
-            newarr[oldlen] = right;
-            return new LSL_List (newarr);
-        }
-
-        public static LSL_List MethListAddList (LSL_List left, LSL_List right)
-        {
-            int leftlen = left.Length;
-            int ritelen = right.Length;
-            object[] newarr = new object[leftlen+ritelen];
-            Array.Copy (left.Data, newarr, leftlen);
-            Array.Copy (right.Data, 0, newarr, leftlen, ritelen);
-            return new LSL_List (newarr);
-        }
-
-        public static LSL_List MethFloatAddList (double left, LSL_List right)
-        {
-            return MethObjAddList (new LSL_Float (left), right);
-        }
-        public static LSL_List MethIntAddList (int left, LSL_List right)
-        {
-            return MethObjAddList (new LSL_Integer (left), right);
-        }
-        public static LSL_List MethKeyAddList (string left, LSL_List right)
-        {
-            return MethObjAddList (new LSL_Key (left), right);
-        }
-        public static LSL_List MethRotAddList (LSL_Rotation left, LSL_List right)
-        {
-            return MethObjAddList (left, right);
-        }
-        public static LSL_List MethStrAddList (string left, LSL_List right)
-        {
-            return MethObjAddList (new LSL_String (left), right);
-        }
-        public static LSL_List MethVecAddList (LSL_Vector left, LSL_List right)
-        {
-            return MethObjAddList (left, right);
-        }
-        public static LSL_List MethObjAddList (object left, LSL_List right)
-        {
-            int oldlen = right.Length;
-            object[] newarr = new object[oldlen+1];
-            newarr[0] = left;
-            Array.Copy (right.Data, 0, newarr, 1, oldlen);
-            return new LSL_List (newarr);
-        }
-
-        public static bool MethListEqList (LSL_List left, LSL_List right)
-        {
-            return left == right;
-        }
-
-        // According to http://wiki.secondlife.com/wiki/LlGetListLength
-        // jackassed LSL allows 'somelist != []' to get the length of a list
-        public static int MethListNeList (LSL_List left, LSL_List right)
-        {
-            int leftlen = left.Length;
-            int ritelen = right.Length;
-            return leftlen - ritelen;
-        }
-
-        public static bool MethRotEqRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left == right;
-        }
-
-        public static bool MethRotNeRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left != right;
-        }
-
-        public static LSL_Rotation MethRotAddRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left + right;
-        }
-
-        public static LSL_Rotation MethRotSubRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left - right;
-        }
-
-        public static LSL_Rotation MethRotMulRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Rotation MethRotDivRot (LSL_Rotation left, LSL_Rotation right)
-        {
-            return left / right;
-        }
-
-        public static bool MethVecEqVec (LSL_Vector left, LSL_Vector right)
-        {
-            return left == right;
-        }
-
-        public static bool MethVecNeVec (LSL_Vector left, LSL_Vector right)
-        {
-            return left != right;
-        }
-
-        public static LSL_Vector MethVecAddVec (LSL_Vector left, LSL_Vector right)
-        {
-            return left + right;
-        }
-
-        public static LSL_Vector MethVecSubVec (LSL_Vector left, LSL_Vector right)
-        {
-            return left - right;
-        }
-
-        public static double MethVecMulVec (LSL_Vector left, LSL_Vector right)
-        {
-            return (double)(left * right).value;
-        }
-
-        public static LSL_Vector MethVecModVec (LSL_Vector left, LSL_Vector right)
-        {
-            return left % right;
-        }
-
-        public static LSL_Vector MethVecMulFloat (LSL_Vector left, double right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Vector MethFloatMulVec (double left, LSL_Vector right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Vector MethVecDivFloat (LSL_Vector left, double right)
-        {
-            return left / right;
-        }
-
-        public static LSL_Vector MethVecMulInt (LSL_Vector left, int right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Vector MethIntMulVec (int left, LSL_Vector right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Vector MethVecDivInt (LSL_Vector left, int right)
-        {
-            return left / right;
-        }
-
-        public static LSL_Vector MethVecMulRot (LSL_Vector left, LSL_Rotation right)
-        {
-            return left * right;
-        }
-
-        public static LSL_Vector MethVecDivRot (LSL_Vector left, LSL_Rotation right)
-        {
-            return left / right;
-        }
-    }
-}

+ 0 - 6258
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs

@@ -1,6258 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * @brief translate a reduced script token into corresponding CIL code.
- * The single script token contains a tokenized and textured version of the whole script file.
- */
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public interface IScriptCodeGen
-    {
-        ScriptMyILGen ilGen { get; } // the output instruction stream
-        void ErrorMsg (Token token, string message);
-        void PushDefaultValue (TokenType type);
-        void PushXMRInst (); 
-    }
-
-    public class ScriptCodeGen : IScriptCodeGen
-    {
-        private static readonly bool DEBUG_STACKCAPRES = false;
-        private static readonly bool DEBUG_TRYSTMT = false;
-
-        public static readonly string OBJECT_CODE_MAGIC = "XMRObjectCode";
-        public static int COMPILED_VERSION_VALUE = 20;  // incremented when compiler changes for compatibility testing
-
-        public static readonly int CALL_FRAME_MEMUSE = 64;
-        public static readonly int STRING_LEN_TO_MEMUSE = 2;
-
-        public static Type xmrInstSuperType = null;  // typeof whatever is actually malloc'd for script instances
-                                                     // - must inherit from XMRInstAbstract
-
-        /*
-         * Static tables that there only needs to be one copy of for all.
-         */
-        private static VarDict legalEventHandlers = CreateLegalEventHandlers ();
-        private static CompValu[]      zeroCompValus = new CompValu[0];
-        private static TokenType[]     zeroArgs      = new TokenType[0];
-        private static TokenTypeBool   tokenTypeBool = new TokenTypeBool   (null);
-        private static TokenTypeExc    tokenTypeExc  = new TokenTypeExc    (null);
-        private static TokenTypeFloat  tokenTypeFlt  = new TokenTypeFloat  (null);
-        private static TokenTypeInt    tokenTypeInt  = new TokenTypeInt    (null);
-        private static TokenTypeObject tokenTypeObj  = new TokenTypeObject (null);
-        private static TokenTypeRot    tokenTypeRot  = new TokenTypeRot    (null);
-        private static TokenTypeStr    tokenTypeStr  = new TokenTypeStr    (null);
-        private static TokenTypeVec    tokenTypeVec  = new TokenTypeVec    (null);
-        private static Type[] instanceTypeArg = new Type[] { typeof (XMRInstAbstract) };
-        private static string[] instanceNameArg = new string[] { "$xmrthis" };
-
-        private static ConstructorInfo lslFloatConstructorInfo = typeof (LSL_Float).GetConstructor (new Type[] { typeof (double) });
-        private static ConstructorInfo lslIntegerConstructorInfo = typeof (LSL_Integer).GetConstructor (new Type[] { typeof (int) });
-        private static ConstructorInfo lslListConstructorInfo = typeof (LSL_List).GetConstructor (new Type[] { typeof (object[]) });
-        public  static ConstructorInfo lslRotationConstructorInfo = typeof (LSL_Rotation).GetConstructor (new Type[] { typeof (double), typeof (double), typeof (double), typeof (double) });
-        private static ConstructorInfo lslStringConstructorInfo = typeof (LSL_String).GetConstructor (new Type[] { typeof (string) });
-        public  static ConstructorInfo lslVectorConstructorInfo = typeof (LSL_Vector).GetConstructor (new Type[] { typeof (double), typeof (double), typeof (double) });
-        private static ConstructorInfo scriptBadCallNoExceptionConstructorInfo = typeof (ScriptBadCallNoException).GetConstructor (new Type[] { typeof (int) });
-        private static ConstructorInfo scriptChangeStateExceptionConstructorInfo = typeof (ScriptChangeStateException).GetConstructor (new Type[] { typeof (int) });
-        private static ConstructorInfo scriptRestoreCatchExceptionConstructorInfo = typeof (ScriptRestoreCatchException).GetConstructor (new Type[] { typeof (Exception) });
-        private static ConstructorInfo scriptUndefinedStateExceptionConstructorInfo = typeof (ScriptUndefinedStateException).GetConstructor (new Type[] { typeof (string) });
-        private static ConstructorInfo sdtClassConstructorInfo = typeof (XMRSDTypeClObj).GetConstructor (new Type[] { typeof (XMRInstAbstract), typeof (int) });
-        private static ConstructorInfo xmrArrayConstructorInfo = typeof (XMR_Array).GetConstructor (new Type[] { typeof (XMRInstAbstract) });
-        private static FieldInfo callModeFieldInfo       = typeof (XMRInstAbstract).GetField ("callMode");
-        private static FieldInfo doGblInitFieldInfo      = typeof (XMRInstAbstract).GetField ("doGblInit");
-        private static FieldInfo ehArgsFieldInfo         = typeof (XMRInstAbstract).GetField ("ehArgs");
-        private static FieldInfo rotationXFieldInfo      = typeof (LSL_Rotation).GetField ("x");
-        private static FieldInfo rotationYFieldInfo      = typeof (LSL_Rotation).GetField ("y");
-        private static FieldInfo rotationZFieldInfo      = typeof (LSL_Rotation).GetField ("z");
-        private static FieldInfo rotationSFieldInfo      = typeof (LSL_Rotation).GetField ("s");
-        private static FieldInfo sdtXMRInstFieldInfo     = typeof (XMRSDTypeClObj).GetField ("xmrInst");
-        private static FieldInfo vectorXFieldInfo        = typeof (LSL_Vector).GetField ("x");
-        private static FieldInfo vectorYFieldInfo        = typeof (LSL_Vector).GetField ("y");
-        private static FieldInfo vectorZFieldInfo        = typeof (LSL_Vector).GetField ("z");
-
-        private static MethodInfo arrayClearMethodInfo   = typeof (XMR_Array).GetMethod ("__pub_clear", new Type[] { });
-        private static MethodInfo arrayCountMethodInfo   = typeof (XMR_Array).GetMethod ("__pub_count", new Type[] { });
-        private static MethodInfo arrayIndexMethodInfo   = typeof (XMR_Array).GetMethod ("__pub_index", new Type[] { typeof (int) });
-        private static MethodInfo arrayValueMethodInfo   = typeof (XMR_Array).GetMethod ("__pub_value", new Type[] { typeof (int) });
-        private static MethodInfo checkRunStackMethInfo  = typeof (XMRInstAbstract).GetMethod ("CheckRunStack", new Type[] { });
-        private static MethodInfo checkRunQuickMethInfo  = typeof (XMRInstAbstract).GetMethod ("CheckRunQuick", new Type[] { });
-        private static MethodInfo ehArgUnwrapFloat       = GetStaticMethod (typeof (TypeCast), "EHArgUnwrapFloat",    new Type[] { typeof (object) });
-        private static MethodInfo ehArgUnwrapInteger     = GetStaticMethod (typeof (TypeCast), "EHArgUnwrapInteger",  new Type[] { typeof (object) });
-        private static MethodInfo ehArgUnwrapRotation    = GetStaticMethod (typeof (TypeCast), "EHArgUnwrapRotation", new Type[] { typeof (object) });
-        private static MethodInfo ehArgUnwrapString      = GetStaticMethod (typeof (TypeCast), "EHArgUnwrapString",   new Type[] { typeof (object) });
-        private static MethodInfo ehArgUnwrapVector      = GetStaticMethod (typeof (TypeCast), "EHArgUnwrapVector",   new Type[] { typeof (object) });
-        private static MethodInfo xmrArrPubIndexMethod   = typeof (XMR_Array).GetMethod ("__pub_index", new Type[] { typeof (int) });
-        private static MethodInfo xmrArrPubValueMethod   = typeof (XMR_Array).GetMethod ("__pub_value", new Type[] { typeof (int) });
-        private static MethodInfo captureStackFrameMethodInfo = typeof (XMRInstAbstract).GetMethod ("CaptureStackFrame", new Type[] { typeof (string), typeof (int), typeof (int) });
-        private static MethodInfo restoreStackFrameMethodInfo = typeof (XMRInstAbstract).GetMethod ("RestoreStackFrame", new Type[] { typeof (string), typeof (int).MakeByRefType () });
-        private static MethodInfo stringCompareMethodInfo     = GetStaticMethod (typeof (String), "Compare", new Type[] { typeof (string), typeof (string), typeof (StringComparison) });
-        private static MethodInfo stringConcat2MethodInfo     = GetStaticMethod (typeof (String), "Concat", new Type[] { typeof (string), typeof (string) });
-        private static MethodInfo stringConcat3MethodInfo     = GetStaticMethod (typeof (String), "Concat", new Type[] { typeof (string), typeof (string), typeof (string) });
-        private static MethodInfo stringConcat4MethodInfo     = GetStaticMethod (typeof (String), "Concat", new Type[] { typeof (string), typeof (string), typeof (string), typeof (string) });
-        private static MethodInfo lslRotationNegateMethodInfo = GetStaticMethod (typeof (ScriptCodeGen), 
-                                                                                 "LSLRotationNegate", 
-                                                                                 new Type[] { typeof (LSL_Rotation) });
-        private static MethodInfo lslVectorNegateMethodInfo = GetStaticMethod (typeof (ScriptCodeGen), 
-                                                                               "LSLVectorNegate", 
-                                                                               new Type[] { typeof (LSL_Vector) });
-        private static MethodInfo scriptRestoreCatchExceptionUnwrap = GetStaticMethod (typeof (ScriptRestoreCatchException), "Unwrap", new Type[] { typeof (Exception) });
-        private static MethodInfo thrownExceptionWrapMethodInfo  = GetStaticMethod (typeof (ScriptThrownException), "Wrap", new Type[] { typeof (object) });
-
-        private static MethodInfo catchExcToStrMethodInfo = GetStaticMethod (typeof (ScriptCodeGen),
-                                                                             "CatchExcToStr",
-                                                                             new Type[] { typeof (Exception) });
-
-        private static MethodInfo consoleWriteMethodInfo      = GetStaticMethod (typeof (ScriptCodeGen), "ConsoleWrite",   new Type[] { typeof (object) });
-        public static void ConsoleWrite (object o)
-        {
-            if (o == null) o = "<<null>>";
-            Console.Write (o.ToString ());
-        }
-
-        public static bool CodeGen (TokenScript tokenScript, BinaryWriter objFileWriter, string sourceHash)
-        {
-            /*
-             * Run compiler such that it has a 'this' context for convenience.
-             */
-            ScriptCodeGen scg = new ScriptCodeGen (tokenScript, objFileWriter, sourceHash);
-
-            /*
-             * Return pointer to resultant script object code.
-             */
-            return !scg.youveAnError;
-        }
-
-        /*
-         * There is one set of these variables for each script being compiled.
-         */
-        private bool mightGetHere = false;
-        private bool youveAnError = false;
-        private BreakContTarg curBreakTarg = null;
-        private BreakContTarg curContTarg  = null;
-        private int lastErrorLine = 0;
-        private int nStates = 0;
-        private string sourceHash;
-        private string lastErrorFile = "";
-        private string[] stateNames;
-        private XMRInstArSizes glblSizes = new XMRInstArSizes ();
-        private Token errorMessageToken = null;
-        private TokenDeclVar curDeclFunc = null;
-        private TokenStmtBlock curStmtBlock = null;
-        private BinaryWriter objFileWriter = null;
-        private TokenScript tokenScript = null;
-        public  int tempCompValuNum = 0;
-        private TokenDeclSDTypeClass currentSDTClass = null;
-
-        private Dictionary<string, int> stateIndices = null;
-
-        // These get cleared at beginning of every function definition
-        private ScriptMyLocal instancePointer;   // holds XMRInstanceSuperType pointer
-        private ScriptMyLabel retLabel  = null;  // where to jump to exit function
-        private ScriptMyLocal retValue  = null;
-        private ScriptMyLocal actCallNo = null;  // for the active try/catch/finally stack or the big one outside them all
-        private LinkedList<CallLabel> actCallLabels = new LinkedList<CallLabel> ();  // for the active try/catch/finally stack or the big one outside them all
-        private LinkedList<CallLabel> allCallLabels = new LinkedList<CallLabel> ();  // this holds each and every one for all stacks in total
-        public  CallLabel openCallLabel = null;  // only one call label can be open at a time
-                                                 // - the call label is open from the time of CallPre() until corresponding CallPost()
-                                                 // - so no non-trivial pushes/pops etc allowed between a CallPre() and a CallPost()
-
-        private ScriptMyILGen _ilGen;
-        public ScriptMyILGen ilGen { get { return _ilGen; } }
-
-        private ScriptCodeGen (TokenScript tokenScript, BinaryWriter objFileWriter, string sourceHash)
-        {
-            this.tokenScript   = tokenScript;
-            this.objFileWriter = objFileWriter;
-            this.sourceHash    = sourceHash;
-
-            try {
-                PerformCompilation ();
-            } catch {
-                // if we've an error, just punt on any exception
-                // it's probably just a null reference from something
-                // not being filled in etc.
-                if (!youveAnError) throw;
-            } finally {
-                objFileWriter = null;
-            }
-        }
-
-        /**
-         * @brief Convert 'tokenScript' to 'objFileWriter' format.
-         *   'tokenScript' is a parsed/reduced abstract syntax tree of the script source file
-         *   'objFileWriter' is a serialized form of the CIL code that we generate
-         */
-        private void PerformCompilation ()
-        {
-            /*
-             * errorMessageToken is used only when the given token doesn't have a
-             * output delegate associated with it such as for backend API functions
-             * that only have one copy for the whole system.  It is kept up-to-date
-             * approximately but is rarely needed so going to assume it doesn't have 
-             * to be exact.
-             */
-            errorMessageToken = tokenScript;
-
-            /*
-             * Set up dictionary to translate state names to their index number.
-             */
-            stateIndices = new Dictionary<string, int> ();
-
-            /*
-             * Assign each state its own unique index.
-             * The default state gets 0.
-             */
-            nStates = 0;
-            tokenScript.defaultState.body.index = nStates ++;
-            stateIndices.Add ("default", 0);
-            foreach (KeyValuePair<string, TokenDeclState> kvp in tokenScript.states) {
-                TokenDeclState declState = kvp.Value;
-                declState.body.index = nStates ++;
-                stateIndices.Add (declState.name.val, declState.body.index);
-            }
-
-            /*
-             * Make up an array that translates state indices to state name strings.
-             */
-            stateNames = new string[nStates];
-            stateNames[0] = "default";
-            foreach (KeyValuePair<string, TokenDeclState> kvp in tokenScript.states) {
-                TokenDeclState declState = kvp.Value;
-                stateNames[declState.body.index] = declState.name.val;
-            }
-
-            /*
-             * Make sure we have delegates for all script-defined functions and methods,
-             * creating anonymous ones if needed.  Note that this includes all property 
-             * getter and setter methods.
-             */
-            foreach (TokenDeclVar declFunc in tokenScript.variablesStack) {
-                if (declFunc.retType != null) {
-                    declFunc.GetDelType ();
-                }
-            }
-            while (true) {
-                bool itIsAGoodDayToDie = true;
-                try {
-                    foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                        itIsAGoodDayToDie = false;
-                        if (sdType is TokenDeclSDTypeClass) {
-                            TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-                            foreach (TokenDeclVar declFunc in sdtClass.members) {
-                                if (declFunc.retType != null) {
-                                    declFunc.GetDelType ();
-                                    if (declFunc.funcNameSig.val.StartsWith ("$ctor(")) {
-                                        // this is for the "$new()" static method that we create below.
-                                        // See GenerateStmtNewobj() etc.
-                                        new TokenTypeSDTypeDelegate (declFunc, sdtClass.MakeRefToken (declFunc), 
-                                                declFunc.argDecl.types, tokenScript);
-                                    }
-                                }
-                            }
-                        }
-                        if (sdType is TokenDeclSDTypeInterface) {
-                            TokenDeclSDTypeInterface sdtIFace = (TokenDeclSDTypeInterface)sdType;
-                            foreach (TokenDeclVar declFunc in sdtIFace.methsNProps) {
-                                if (declFunc.retType != null) {
-                                    declFunc.GetDelType ();
-                                }
-                            }
-                        }
-                        itIsAGoodDayToDie = true;
-                    }
-                    break;
-                } catch (InvalidOperationException) {
-                    if (!itIsAGoodDayToDie) throw;
-                    // fetching the delegate created an anonymous entry in tokenScript.sdSrcTypesValues
-                    // which made the foreach statement puque, so start over...
-                }
-            }
-
-            /*
-             * No more types can be defined or we won't be able to write them to the object file.
-             */
-            tokenScript.sdSrcTypesSeal ();
-
-            /*
-             * Assign all global variables a slot in its corresponding XMRInstance.gbl<Type>s[] array.
-             * Global variables are simply elements of those arrays at runtime, thus we don't need to create
-             * an unique class for each script, we can just use XMRInstance as is for all.
-             */
-            foreach (TokenDeclVar declVar in tokenScript.variablesStack) {
-
-                /*
-                 * Omit 'constant' variables as they are coded inline so don't need a slot.
-                 */
-                if (declVar.constant) continue;
-
-                /*
-                 * Do functions later.
-                 */
-                if (declVar.retType != null) continue;
-
-                /*
-                 * Create entry in the value array for the variable or property.
-                 */
-                declVar.location = new CompValuGlobalVar (declVar, glblSizes);
-            }
-
-            /*
-             * Likewise for any static fields in script-defined classes.
-             * They can be referenced anywhere by <typename>.<fieldname>, see 
-             * GenerateFromLValSField().
-             */
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                if (!(sdType is TokenDeclSDTypeClass)) continue;
-                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-
-                foreach (TokenDeclVar declVar in sdtClass.members) {
-
-                    /*
-                     * Omit 'constant' variables as they are coded inline so don't need a slot.
-                     */
-                    if (declVar.constant) continue;
-
-                    /*
-                     * Do methods later.
-                     */
-                    if (declVar.retType != null) continue;
-
-                    /*
-                     * Ignore non-static fields for now.
-                     * They get assigned below.
-                     */
-                    if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) == 0) continue;
-
-                    /*
-                     * Create entry in the value array for the static field or static property.
-                     */
-                    declVar.location = new CompValuGlobalVar (declVar, glblSizes);
-                }
-            }
-
-            /*
-             * Assign slots for all interface method prototypes.
-             * These indices are used to index the array of delegates that holds a class' implementation of an 
-             * interface.
-             * Properties do not get a slot because they aren't called as such.  But their corresponding
-             * <name>$get() and <name>$set(<type>) methods are in the table and they each get a slot.
-             */
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                if (!(sdType is TokenDeclSDTypeInterface)) continue;
-                TokenDeclSDTypeInterface sdtIFace = (TokenDeclSDTypeInterface)sdType;
-                int vti = 0;
-                foreach (TokenDeclVar im in sdtIFace.methsNProps) {
-                    if ((im.getProp == null) && (im.setProp == null)) {
-                        im.vTableIndex = vti ++;
-                    }
-                }
-            }
-
-            /*
-             * Assign slots for all instance fields and virtual methods of script-defined classes.
-             */
-            int maxExtends = tokenScript.sdSrcTypesCount;
-            bool didOne;
-            do {
-                didOne = false;
-                foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                    if (!(sdType is TokenDeclSDTypeClass)) continue;
-                    TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-                    if (sdtClass.slotsAssigned) continue;
-
-                    /*
-                     * If this class extends another, the extended class has to already 
-                     * be set up, because our slots add on to the end of the extended class.
-                     */
-                    TokenDeclSDTypeClass extends = sdtClass.extends;
-                    if (extends != null) {
-                        if (!extends.slotsAssigned) continue;
-                        sdtClass.instSizes     = extends.instSizes;
-                        sdtClass.numVirtFuncs  = extends.numVirtFuncs;
-                        sdtClass.numInterfaces = extends.numInterfaces;
-
-                        int n = maxExtends;
-                        for (TokenDeclSDTypeClass ex = extends; ex != null; ex = ex.extends) {
-                            if (-- n < 0) break;
-                        }
-                        if (n < 0) {
-                            ErrorMsg (sdtClass, "loop in extended classes");
-                            sdtClass.slotsAssigned = true;
-                            continue;
-                        }
-                    }
-
-                    /*
-                     * Extended class's slots all assigned, assign our instance fields 
-                     * slots in the XMRSDTypeClObj arrays.
-                     */
-                    foreach (TokenDeclVar declVar in sdtClass.members) {
-                        if (declVar.retType != null) continue;
-                        if (declVar.constant) continue;
-                        if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0) continue;
-                        if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                            declVar.type.AssignVarSlot (declVar, sdtClass.instSizes);
-                        }
-                    }
-
-                    /*
-                     * ... and assign virtual method vtable slots.
-                     *
-                     *                   - : error if any overridden method, doesn't need a slot
-                     *            abstract : error if any overridden method, alloc new slot but leave it empty
-                     *                 new : ignore any overridden method, doesn't need a slot
-                     *        new abstract : ignore any overridden method, alloc new slot but leave it empty
-                     *            override : must have overridden abstract/virtual, use old slot
-                     *   override abstract : must have overridden abstract, use old slot but it is still empty
-                     *              static : error if any overridden method, doesn't need a slot
-                     *          static new : ignore any overridden method, doesn't need a slot
-                     *             virtual : error if any overridden method, alloc new slot and fill it in
-                     *         virtual new : ignore any overridden method, alloc new slot and fill it in
-                     */
-                    foreach (TokenDeclVar declFunc in sdtClass.members) {
-                        if (declFunc.retType == null) continue;
-                        curDeclFunc = declFunc;
-
-                        /*
-                         * See if there is a method in an extended class that this method overshadows.
-                         * If so, check for various conflicts.
-                         * In any case, SDT_NEW on our method means to ignore any overshadowed method.
-                         */
-                        string declLongName = sdtClass.longName.val + "." + declFunc.funcNameSig.val;
-                        uint declFlags = declFunc.sdtFlags;
-                        TokenDeclVar overridden = null;
-                        if ((declFlags & ScriptReduce.SDT_NEW) == 0) {
-                            for (TokenDeclSDTypeClass sdtd = extends; sdtd != null; sdtd = sdtd.extends) {
-                                overridden = FindExactWithRet (sdtd.members, declFunc.name, declFunc.retType, declFunc.argDecl.types);
-                                if (overridden != null) break;
-                            }
-                        }
-                        if (overridden != null) do {
-                            string overLongName = overridden.sdtClass.longName.val;
-                            uint overFlags = overridden.sdtFlags;
-
-                            /*
-                             * See if overridden method allows itself to be overridden.
-                             */
-                            if ((overFlags & ScriptReduce.SDT_ABSTRACT) != 0) {
-                                if ((declFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_OVERRIDE)) == 0) {
-                                    ErrorMsg (declFunc, declLongName + " overshadows abstract " + overLongName + " but is not marked abstract, new or override");
-                                    break;
-                                }
-                            } else if ((overFlags & ScriptReduce.SDT_FINAL) != 0) {
-                                ErrorMsg (declFunc, declLongName + " overshadows final " + overLongName + " but is not marked new");
-                            } else if ((overFlags & (ScriptReduce.SDT_OVERRIDE | ScriptReduce.SDT_VIRTUAL)) != 0) {
-                                if ((declFlags & (ScriptReduce.SDT_NEW | ScriptReduce.SDT_OVERRIDE)) == 0) {
-                                    ErrorMsg (declFunc, declLongName + " overshadows virtual " + overLongName + " but is not marked new or override");
-                                    break;
-                                }
-                            } else {
-                                ErrorMsg (declFunc, declLongName + " overshadows non-virtual " + overLongName + " but is not marked new");
-                                break;
-                            }
-
-                            /*
-                             * See if our method is capable of overriding the other method.
-                             */
-                            if ((declFlags & ScriptReduce.SDT_ABSTRACT) != 0) {
-                                if ((overFlags & ScriptReduce.SDT_ABSTRACT) == 0) {
-                                    ErrorMsg (declFunc, declLongName + " abstract overshadows non-abstract " + overLongName + " but is not marked new");
-                                    break;
-                                }
-                            } else if ((declFlags & ScriptReduce.SDT_OVERRIDE) != 0) {
-                                if ((overFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_OVERRIDE | ScriptReduce.SDT_VIRTUAL)) == 0) {
-                                    ErrorMsg (declFunc, declLongName + " override overshadows non-abstract/non-virtual " + overLongName);
-                                    break;
-                                }
-                            } else {
-                                ErrorMsg (declFunc, declLongName + " overshadows " + overLongName + " but is not marked new");
-                                break;
-                            }
-                        } while (false);
-
-                        /*
-                         * Now we can assign it a vtable slot if it needs one (ie, it is virtual).
-                         */
-                        declFunc.vTableIndex = -1;
-                        if (overridden != null) {
-                            declFunc.vTableIndex = overridden.vTableIndex;
-                        } else if ((declFlags & ScriptReduce.SDT_OVERRIDE) != 0) {
-                            ErrorMsg (declFunc, declLongName + " marked override but nothing matching found that it overrides");
-                        }
-                        if ((declFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_VIRTUAL)) != 0) {
-                            declFunc.vTableIndex = sdtClass.numVirtFuncs ++;
-                        }
-                    }
-                    curDeclFunc = null;
-
-                    /*
-                     * ... and assign implemented interface slots.
-                     * Note that our implementations of a given interface is completely independent of any 
-                     * rootward class's implementation of that same interface.
-                     */
-                    int nIFaces        = sdtClass.numInterfaces + sdtClass.implements.Count;
-                    sdtClass.iFaces    = new TokenDeclSDTypeInterface[nIFaces];
-                    sdtClass.iImplFunc = new TokenDeclVar[nIFaces][];
-                    for (int i = 0; i < sdtClass.numInterfaces; i ++) {
-                        sdtClass.iFaces[i]    = extends.iFaces[i];
-                        sdtClass.iImplFunc[i] = extends.iImplFunc[i];
-                    }
-
-                    foreach (TokenDeclSDTypeInterface intf in sdtClass.implements) {
-                        int i = sdtClass.numInterfaces ++;
-                        sdtClass.iFaces[i] = intf;
-                        sdtClass.intfIndices.Add (intf.longName.val, i);
-                        int nMeths = 0;
-                        foreach (TokenDeclVar m in intf.methsNProps) {
-                            if ((m.getProp == null) && (m.setProp == null)) nMeths ++;
-                        }
-                        sdtClass.iImplFunc[i] = new TokenDeclVar[nMeths];
-                    }
-
-                    foreach (TokenDeclVar classMeth in sdtClass.members) {
-                        if (classMeth.retType == null) continue;
-                        curDeclFunc = classMeth;
-                        for (TokenIntfImpl intfImpl = classMeth.implements; intfImpl != null; intfImpl = (TokenIntfImpl)intfImpl.nextToken) {
-
-                            /*
-                             * One of the class methods implements an interface method.
-                             * Try to find the interface method that is implemented and verify its signature.
-                             */
-                            TokenDeclSDTypeInterface intfType = intfImpl.intfType.decl;
-                            TokenDeclVar intfMeth = FindExactWithRet (intfType.methsNProps, intfImpl.methName, classMeth.retType, classMeth.argDecl.types);
-                            if (intfMeth == null) {
-                                ErrorMsg (intfImpl, "interface does not define method " + intfImpl.methName.val + classMeth.argDecl.GetArgSig ());
-                                continue;
-                            }
-
-                            /*
-                             * See if this class was declared to implement that interface.
-                             */
-                            bool found = false;
-                            foreach (TokenDeclSDTypeInterface intf in sdtClass.implements) {
-                                if (intf == intfType) {
-                                    found = true;
-                                    break;
-                                }
-                            }
-                            if (!found) {
-                                ErrorMsg (intfImpl, "class not declared to implement " + intfType.longName.val);
-                                continue;
-                            }
-
-                            /*
-                             * Get index in iFaces[] and iImplFunc[] arrays.
-                             * Start scanning from the end in case one of our rootward classes also implements the interface.
-                             * We should always be successful because we know by now that this class implements the interface.
-                             */
-                            int i;
-                            for (i = sdtClass.numInterfaces; -- i >= 0;) {
-                                if (sdtClass.iFaces[i] == intfType) break;
-                            }
-
-                            /*
-                             * Now remember which of the class methods implements that interface method.
-                             */
-                            int j = intfMeth.vTableIndex;
-                            if (sdtClass.iImplFunc[i][j] != null) {
-                                ErrorMsg (intfImpl, "also implemented by " + sdtClass.iImplFunc[i][j].funcNameSig.val);
-                                continue;
-                            }
-                            sdtClass.iImplFunc[i][j] = classMeth;
-                        }
-                    }
-                    curDeclFunc = null;
-
-                    /*
-                     * Now make sure this class implements all methods for all declared interfaces.
-                     */
-                    for (int i = sdtClass.numInterfaces - sdtClass.implements.Count; i < sdtClass.numInterfaces; i ++) {
-                        TokenDeclVar[] implementations = sdtClass.iImplFunc[i];
-                        for (int j = implementations.Length; -- j >= 0;) {
-                            if (implementations[j] == null) {
-                                TokenDeclSDTypeInterface intf = sdtClass.iFaces[i];
-                                TokenDeclVar meth = null;
-                                foreach (TokenDeclVar im in intf.methsNProps) {
-                                    if (im.vTableIndex == j) {
-                                        meth = im;
-                                        break;
-                                    }
-                                }
-                                ErrorMsg (sdtClass, "does not implement " + intf.longName.val + "." + meth.funcNameSig.val);
-                            }
-                        }
-                    }
-
-                    /*
-                     * All slots for this class have been assigned.
-                     */
-                    sdtClass.slotsAssigned = true;
-                    didOne = true;
-                }
-            } while (didOne);
-
-            /*
-             * Compute final values for all variables/fields declared as 'constant'.
-             * Note that there may be forward references.
-             */
-            do {
-                didOne = false;
-                foreach (TokenDeclVar tdv in tokenScript.variablesStack) {
-                    if (tdv.constant && !(tdv.init is TokenRValConst)) {
-                        tdv.init = tdv.init.TryComputeConstant (LookupInitConstants, ref didOne);
-                    }
-                }
-                foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                    if (!(sdType is TokenDeclSDTypeClass)) continue;
-                    currentSDTClass = (TokenDeclSDTypeClass)sdType;
-                    foreach (TokenDeclVar tdv in currentSDTClass.members) {
-                        if (tdv.constant && !(tdv.init is TokenRValConst)) {
-                            tdv.init = tdv.init.TryComputeConstant (LookupInitConstants, ref didOne);
-                        }
-                    }
-                }
-                currentSDTClass = null;
-            } while (didOne);
-
-            /*
-             * Now we should be able to assign all those constants their type and location.
-             */
-            foreach (TokenDeclVar tdv in tokenScript.variablesStack) {
-                if (tdv.constant) {
-                    if (tdv.init is TokenRValConst) {
-                        TokenRValConst rvc = (TokenRValConst)tdv.init;
-                        tdv.type = rvc.tokType;
-                        tdv.location = rvc.GetCompValu ();
-                    } else {
-                        ErrorMsg (tdv, "value is not constant");
-                    }
-                }
-            }
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                if (!(sdType is TokenDeclSDTypeClass)) continue;
-                currentSDTClass = (TokenDeclSDTypeClass)sdType;
-                foreach (TokenDeclVar tdv in currentSDTClass.members) {
-                    if (tdv.constant) {
-                        if (tdv.init is TokenRValConst) {
-                            TokenRValConst rvc = (TokenRValConst)tdv.init;
-                            tdv.type = rvc.tokType;
-                            tdv.location = rvc.GetCompValu ();
-                        } else {
-                            ErrorMsg (tdv, "value is not constant");
-                        }
-                    }
-                }
-            }
-            currentSDTClass = null;
-
-            /*
-             * For all classes that define all the methods needed for the class, ie, they aren't abstract,
-             * define a static class.$new() method with same args as the $ctor(s).  This will allow the
-             * class to be instantiated via the new operator.
-             */
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                if (!(sdType is TokenDeclSDTypeClass)) continue;
-                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-
-                /*
-                 * See if the class as it stands would be able to fill every slot of its vtable.
-                 */
-                bool[] filled = new bool[sdtClass.numVirtFuncs];
-                int numFilled = 0;
-                for (TokenDeclSDTypeClass sdtc = sdtClass; sdtc != null; sdtc = sdtc.extends) {
-                    foreach (TokenDeclVar tdf in sdtc.members) {
-                        if ((tdf.retType != null) && (tdf.vTableIndex >= 0) && ((tdf.sdtFlags & ScriptReduce.SDT_ABSTRACT) == 0)) {
-                            if (!filled[tdf.vTableIndex]) {
-                                filled[tdf.vTableIndex] = true;
-                                numFilled ++;
-                            }
-                        }
-                    }
-                }
-
-                /*
-                 * If so, define a static class.$new() method for every constructor defined for the class.
-                 * Give it the same access (private/protected/public) as the script declared for the constructor.
-                 * Note that the reducer made sure there is at least a default constructor for every class.
-                 */
-                if (numFilled >= sdtClass.numVirtFuncs) {
-                    List<TokenDeclVar> newobjDeclFuncs = new List<TokenDeclVar> ();
-                    foreach (TokenDeclVar ctorDeclFunc in sdtClass.members) {
-                        if ((ctorDeclFunc.funcNameSig != null) && ctorDeclFunc.funcNameSig.val.StartsWith ("$ctor(")) {
-                            TokenDeclVar newobjDeclFunc = DefineNewobjFunc (ctorDeclFunc);
-                            newobjDeclFuncs.Add (newobjDeclFunc);
-                        }
-                    }
-                    foreach (TokenDeclVar newobjDeclFunc in newobjDeclFuncs) {
-                        sdtClass.members.AddEntry (newobjDeclFunc);
-                    }
-                }
-            }
-
-            /*
-             * Write fixed portion of object file.
-             */
-            objFileWriter.Write (OBJECT_CODE_MAGIC.ToCharArray ());
-            objFileWriter.Write (COMPILED_VERSION_VALUE);
-            objFileWriter.Write (sourceHash);
-            objFileWriter.Write (tokenScript.expiryDays);
-            glblSizes.WriteToFile (objFileWriter);
-
-            objFileWriter.Write (nStates);
-            for (int i = 0; i < nStates; i ++) {
-                objFileWriter.Write (stateNames[i]);
-            }
-
-            /*
-             * For debugging, we also write out global variable array slot assignments.
-             */
-            foreach (TokenDeclVar declVar in tokenScript.variablesStack) {
-                if (declVar.retType == null) {
-                    WriteOutGblAssignment ("", declVar);
-                }
-            }
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                if (!(sdType is TokenDeclSDTypeClass)) continue;
-                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-                foreach (TokenDeclVar declVar in sdtClass.members) {
-                    if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0) {
-                        WriteOutGblAssignment (sdtClass.longName.val + ".", declVar);
-                    }
-                }
-            }
-            objFileWriter.Write ("");
-
-            /*
-             * Write out script-defined types.
-             */
-            foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                objFileWriter.Write (sdType.longName.val);
-                sdType.WriteToFile (objFileWriter);
-            }
-            objFileWriter.Write ("");
-
-            /*
-             * Output function headers then bodies.
-             * Do all headers first in case bodies do forward references.
-             * Do both global functions, script-defined class static methods and 
-             * script-defined instance methods, as we handle the differences
-             * during compilation of the functions/methods themselves.
-             */
-            for (int pass = 0; pass < 2; pass ++) {
-                foreach (TokenDeclVar declFunc in tokenScript.variablesStack) {
-                    if (declFunc.retType != null) {
-                        if (pass == 0) GenerateMethodHeader (declFunc);
-                                  else GenerateMethodBody   (declFunc);
-                    }
-                }
-                foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                    if (sdType is TokenDeclSDTypeClass) {
-                        TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
-                        foreach (TokenDeclVar declFunc in sdtClass.members) {
-                            if ((declFunc.retType != null) && ((declFunc.sdtFlags & ScriptReduce.SDT_ABSTRACT) == 0)) {
-                                if (pass == 0) GenerateMethodHeader (declFunc);
-                                          else GenerateMethodBody   (declFunc);
-                            }
-                        }
-                    }
-                }
-            }
-
-            /*
-             * Output default state event handler functions.
-             * Each event handler is a private static method named 'default <eventname>'.
-             * Splice in a default state_entry() handler if none defined so we can init global vars.
-             */
-            TokenDeclVar defaultStateEntry = null;
-            for (defaultStateEntry = tokenScript.defaultState.body.eventFuncs;
-                 defaultStateEntry != null;
-                 defaultStateEntry = (TokenDeclVar)defaultStateEntry.nextToken) {
-                if (defaultStateEntry.funcNameSig.val == "state_entry()") break;
-            }
-            if (defaultStateEntry == null) {
-                defaultStateEntry               = new TokenDeclVar   (tokenScript.defaultState.body, null, tokenScript);
-                defaultStateEntry.name          = new TokenName      (tokenScript.defaultState.body, "state_entry");
-                defaultStateEntry.retType       = new TokenTypeVoid  (tokenScript.defaultState.body);
-                defaultStateEntry.argDecl       = new TokenArgDecl   (tokenScript.defaultState.body);
-                defaultStateEntry.body          = new TokenStmtBlock (tokenScript.defaultState.body);
-                defaultStateEntry.body.function = defaultStateEntry;
-
-                defaultStateEntry.nextToken = tokenScript.defaultState.body.eventFuncs;
-                tokenScript.defaultState.body.eventFuncs = defaultStateEntry;
-            }
-            GenerateStateEventHandlers ("default", tokenScript.defaultState.body);
-
-            /*
-             * Output script-defined state event handler methods.
-             * Each event handler is a private static method named <statename> <eventname>
-             */
-            foreach (KeyValuePair<string, TokenDeclState> kvp in tokenScript.states) {
-                TokenDeclState declState = kvp.Value;
-                GenerateStateEventHandlers (declState.name.val, declState.body);
-            }
-
-            ScriptObjWriter.TheEnd (objFileWriter);
-        }
-
-        /**
-         * @brief Write out what slot was assigned for a global or sdtclass static variable.
-         *        Constants, functions, instance fields, methods, properties do not have slots in the global variables arrays.
-         */
-        private void WriteOutGblAssignment (string pfx, TokenDeclVar declVar)
-        {
-            if (!declVar.constant && (declVar.retType == null) && (declVar.getProp == null) && (declVar.setProp == null)) {
-                objFileWriter.Write (pfx + declVar.name.val);    // string
-                objFileWriter.Write (declVar.vTableArray.Name);  // string
-                objFileWriter.Write (declVar.vTableIndex);       // int
-            }
-        }
-
-        /**
-         * @brief generate event handler code
-         * Writes out a function definition for each state handler
-         * named <statename> <eventname>
-         *
-         * However, each has just 'XMRInstance __sw' as its single argument
-         * and each of its user-visible argments is extracted from __sw.ehArgs[].
-         *
-         * So we end up generating something like this:
-         *
-         *   private static void <statename> <eventname>(XMRInstance __sw)
-         *   {
-         *      <typeArg0> <nameArg0> = (<typeArg0>)__sw.ehArgs[0];
-         *      <typeArg1> <nameArg1> = (<typeArg1>)__sw.ehArgs[1];
-         *
-         *      ... script code ...
-         *   }
-         *
-         * The continuations code assumes there will be no references to ehArgs[]
-         * after the first call to CheckRun() as CheckRun() makes no attempt to
-         * serialize the ehArgs[] array, as doing so would be redundant.  Any values
-         * from ehArgs[] that are being used will be in local stack variables and
-         * thus preserved that way.
-         */
-        private void GenerateStateEventHandlers (string statename, TokenStateBody body)
-        {
-            Dictionary<string,TokenDeclVar> statehandlers = new Dictionary<string,TokenDeclVar> ();
-            for (Token t = body.eventFuncs; t != null; t = t.nextToken) {
-                TokenDeclVar tdv = (TokenDeclVar)t;
-                string eventname = tdv.GetSimpleName ();
-                if (statehandlers.ContainsKey (eventname)) {
-                    ErrorMsg (tdv, "event handler " + eventname + " already defined for state " + statename);
-                } else {
-                    statehandlers.Add (eventname, tdv);
-                    GenerateEventHandler (statename, tdv);
-                }
-            }
-        }
-
-        private void GenerateEventHandler (string statename, TokenDeclVar declFunc)
-        {
-            string eventname = declFunc.GetSimpleName ();
-            TokenArgDecl argDecl = declFunc.argDecl;
-
-            /*
-             * Make sure event handler name is valid and that number and type of arguments is correct.
-             * Apparently some scripts exist with fewer than correct number of args in their declaration 
-             * so allow for that.  It is ok because the handlers are called with the arguments in an
-             * object[] array, and we just won't access the missing argments in the vector.  But the 
-             * specified types must match one of the prototypes in legalEventHandlers.
-             */
-            TokenDeclVar protoDeclFunc = legalEventHandlers.FindExact (eventname, argDecl.types);
-            if (protoDeclFunc == null) {
-                ErrorMsg (declFunc, "unknown event handler " + eventname + argDecl.GetArgSig ());
-                return;
-            }
-
-            /*
-             * Output function header.
-             * They just have the XMRInstAbstract pointer as the one argument.
-             */
-            string functionName = statename + " " + eventname;
-            _ilGen = new ScriptObjWriter (tokenScript, 
-                                          functionName,
-                                          typeof (void),
-                                          instanceTypeArg,
-                                          instanceNameArg,
-                                          objFileWriter);
-            StartFunctionBody (declFunc);
-
-            /*
-             * Create a temp to hold XMRInstanceSuperType version of arg 0.
-             */
-            instancePointer = ilGen.DeclareLocal (xmrInstSuperType, "__xmrinst");
-            ilGen.Emit (declFunc, OpCodes.Ldarg_0);
-            ilGen.Emit (declFunc, OpCodes.Castclass, xmrInstSuperType);
-            ilGen.Emit (declFunc, OpCodes.Stloc, instancePointer);
-
-            /*
-             * Output args as variable definitions and initialize each from __sw.ehArgs[].
-             * If the script writer goofed, the typecast will complain.
-             */
-            int nArgs = argDecl.vars.Length;
-            for (int i = 0; i < nArgs; i ++) {
-
-                /*
-                 * Say that the argument variable is going to be located in a local var.
-                 */
-                TokenDeclVar argVar = argDecl.vars[i];
-                TokenType argTokType = argVar.type;
-                CompValuLocalVar local = new CompValuLocalVar (argTokType, argVar.name.val, this);
-                argVar.location = local;
-
-                /*
-                 * Copy from the ehArgs[i] element to the temp var.
-                 * Cast as needed, there is a lot of craziness like OpenMetaverse.Quaternion.
-                 */
-                local.PopPre (this, argVar.name);
-                PushXMRInst ();                                          // instance
-                ilGen.Emit (declFunc, OpCodes.Ldfld, ehArgsFieldInfo);   // instance.ehArgs (array of objects)
-                ilGen.Emit (declFunc, OpCodes.Ldc_I4, i);                // array index = i
-                ilGen.Emit (declFunc, OpCodes.Ldelem, typeof (object));  // select the argument we want
-                TokenType stkTokType = tokenTypeObj;                     // stack has a type 'object' on it now
-                Type argSysType = argTokType.ToSysType ();               // this is the type the script expects
-                if (argSysType == typeof (double)) {                // LSL_Float/double -> double
-                    ilGen.Emit (declFunc, OpCodes.Call, ehArgUnwrapFloat);
-                    stkTokType = tokenTypeFlt;                       // stack has a type 'double' on it now
-                }
-                if (argSysType == typeof (int)) {                        // LSL_Integer/int -> int
-                    ilGen.Emit (declFunc, OpCodes.Call, ehArgUnwrapInteger);
-                    stkTokType = tokenTypeInt;                       // stack has a type 'int' on it now
-                }
-                if (argSysType == typeof (LSL_List)) {                   // LSL_List -> LSL_List
-                    TypeCast.CastTopOfStack (this, argVar.name, stkTokType, argTokType, true);
-                    stkTokType = argTokType;                         // stack has a type 'LSL_List' on it now
-                }
-                if (argSysType == typeof (LSL_Rotation)) {               // OpenMetaverse.Quaternion/LSL_Rotation -> LSL_Rotation
-                    ilGen.Emit (declFunc, OpCodes.Call, ehArgUnwrapRotation);
-                    stkTokType = tokenTypeRot;                       // stack has a type 'LSL_Rotation' on it now
-                }
-                if (argSysType == typeof (string)) {                     // LSL_Key/LSL_String/string -> string
-                    ilGen.Emit (declFunc, OpCodes.Call, ehArgUnwrapString);
-                    stkTokType = tokenTypeStr;                       // stack has a type 'string' on it now
-                }
-                if (argSysType == typeof (LSL_Vector)) {                 // OpenMetaverse.Vector3/LSL_Vector -> LSL_Vector
-                    ilGen.Emit (declFunc, OpCodes.Call, ehArgUnwrapVector);
-                    stkTokType = tokenTypeVec;                       // stack has a type 'LSL_Vector' on it now
-                }
-                local.PopPost (this, argVar.name, stkTokType);           // pop stack type into argtype
-            }
-
-            /*
-             * Output code for the statements and clean up.
-             */
-            GenerateFuncBody ();
-        }
-
-        /**
-         * @brief generate header for an arbitrary script-defined global function.
-         * @param declFunc = function being defined
-         */
-        private void GenerateMethodHeader (TokenDeclVar declFunc)
-        {
-            curDeclFunc = declFunc;
-
-            /*
-             * Make up array of all argument types as seen by the code generator.
-             * We splice in XMRInstanceSuperType or XMRSDTypeClObj for the first 
-             * arg as the function itself is static, followed by script-visible
-             * arg types.
-             */
-            TokenArgDecl argDecl = declFunc.argDecl;
-            int nArgs = argDecl.vars.Length;
-            Type[] argTypes = new Type[nArgs+1];
-            string[] argNames = new string[nArgs+1];
-            if (IsSDTInstMethod ()) {
-                argTypes[0] = typeof (XMRSDTypeClObj);
-                argNames[0] = "$sdtthis";
-            } else {
-                argTypes[0] = xmrInstSuperType;
-                argNames[0] = "$xmrthis";
-            }
-            for (int i = 0; i < nArgs; i ++) {
-                argTypes[i+1] = argDecl.vars[i].type.ToSysType ();
-                argNames[i+1] = argDecl.vars[i].name.val;
-            }
-
-            /*
-             * Set up entrypoint.
-             */
-            string objCodeName = declFunc.GetObjCodeName ();
-            declFunc.ilGen = new ScriptObjWriter (tokenScript, 
-                                                  objCodeName,
-                                                  declFunc.retType.ToSysType (),
-                                                  argTypes,
-                                                  argNames,
-                                                  objFileWriter);
-
-            /*
-             * This says how to generate a call to the function and to get a delegate.
-             */
-            declFunc.location = new CompValuGlobalMeth (declFunc);
-
-            curDeclFunc = null;
-        }
-
-        /**
-         * @brief generate code for an arbitrary script-defined function.
-         * @param name = name of the function
-         * @param argDecl = argument declarations
-         * @param body = function's code body
-         */
-        private void GenerateMethodBody (TokenDeclVar declFunc)
-        {
-            /*
-             * Set up code generator for the function's contents.
-             */
-            _ilGen = declFunc.ilGen;
-            StartFunctionBody (declFunc);
-
-            /*
-             * Create a temp to hold XMRInstanceSuperType version of arg 0.
-             * For most functions, arg 0 is already XMRInstanceSuperType.
-             * But for script-defined class instance methods, arg 0 holds
-             * the XMRSDTypeClObj pointer and so we read the XMRInstAbstract
-             * pointer from its XMRSDTypeClObj.xmrInst field then cast it to
-             * XMRInstanceSuperType.
-             */
-            if (IsSDTInstMethod ()) {
-                instancePointer = ilGen.DeclareLocal (xmrInstSuperType, "__xmrinst");
-                ilGen.Emit (declFunc, OpCodes.Ldarg_0);
-                ilGen.Emit (declFunc, OpCodes.Ldfld, sdtXMRInstFieldInfo);
-                ilGen.Emit (declFunc, OpCodes.Castclass, xmrInstSuperType);
-                ilGen.Emit (declFunc, OpCodes.Stloc, instancePointer);
-            }
-
-            /*
-             * Define location of all script-level arguments so script body can access them.
-             * The argument indices need to have +1 added to them because XMRInstance or 
-             * XMRSDTypeClObj is spliced in at arg 0.
-             */
-            TokenArgDecl argDecl = declFunc.argDecl;
-            int nArgs = argDecl.vars.Length;
-            for (int i = 0; i < nArgs; i ++) {
-                TokenDeclVar argVar = argDecl.vars[i];
-                argVar.location = new CompValuArg (argVar.type, i + 1);
-            }
-
-            /*
-             * Output code for the statements and clean up.
-             */
-            GenerateFuncBody ();
-        }
-
-        private void StartFunctionBody (TokenDeclVar declFunc)
-        {
-            /*
-             * Start current function being processed.
-             * Set 'mightGetHere' as the code at the top is always executed.
-             */
-            instancePointer = null;
-            mightGetHere    = true;
-            curBreakTarg    = null;
-            curContTarg     = null;
-            curDeclFunc     = declFunc;
-
-            /*
-             * Start generating code.
-             */
-            ((ScriptObjWriter)ilGen).BegMethod ();
-        }
-
-        /**
-         * @brief Define function for a script-defined type's <typename>.$new(<argsig>) method.
-         *        See GenerateStmtNewobj() for more info.
-         */
-        private TokenDeclVar DefineNewobjFunc (TokenDeclVar ctorDeclFunc)
-        {
-            /*
-             * Set up 'static classname $new(params-same-as-ctor) { }'.
-             */
-            TokenDeclVar newobjDeclFunc = new TokenDeclVar (ctorDeclFunc, null, tokenScript);
-            newobjDeclFunc.name         = new TokenName (newobjDeclFunc, "$new");
-            newobjDeclFunc.retType      = ctorDeclFunc.sdtClass.MakeRefToken (newobjDeclFunc);
-            newobjDeclFunc.argDecl      = ctorDeclFunc.argDecl;
-            newobjDeclFunc.sdtClass     = ctorDeclFunc.sdtClass;
-            newobjDeclFunc.sdtFlags     = ScriptReduce.SDT_STATIC | ctorDeclFunc.sdtFlags;
-
-            /*
-             * Declare local variable named '$objptr' in a frame just under 
-             * what the '$new(...)' function's arguments are declared in.
-             */
-            TokenDeclVar objptrVar = new TokenDeclVar (newobjDeclFunc, newobjDeclFunc, tokenScript);
-            objptrVar.type         = newobjDeclFunc.retType;
-            objptrVar.name         = new TokenName (newobjDeclFunc, "$objptr");
-            VarDict newFrame       = new VarDict (false);
-            newFrame.outerVarDict  = ctorDeclFunc.argDecl.varDict;
-            newFrame.AddEntry (objptrVar);
-
-            /*
-             * Set up '$objptr.$ctor'
-             */
-            TokenLValName objptrLValName  = new TokenLValName (objptrVar.name, newFrame);
-                                                                                   // ref a var by giving its name
-            TokenLValIField objptrDotCtor = new TokenLValIField (newobjDeclFunc);  // an instance member reference
-            objptrDotCtor.baseRVal        = objptrLValName;                        // '$objptr'
-            objptrDotCtor.fieldName       = ctorDeclFunc.name;                     // '.' '$ctor'
-
-            /*
-             * Set up '$objptr.$ctor(arglist)' call for use in the '$new(...)' body.
-             * Copy the arglist from the constructor declaration so triviality 
-             * processing will pick the correct overloaded constructor.
-             */
-            TokenRValCall callCtorRVal = new TokenRValCall (newobjDeclFunc);   // doing a call of some sort
-            callCtorRVal.meth          = objptrDotCtor;                        // calling $objptr.$ctor()
-            TokenDeclVar[] argList     = newobjDeclFunc.argDecl.vars;          // get args $new() was declared with
-            callCtorRVal.nArgs         = argList.Length;                       // ...that is nArgs we are passing to $objptr.$ctor()
-            for (int i = argList.Length; -- i >= 0;) {
-                TokenDeclVar arg          = argList[i];                    // find out about one of the args
-                TokenLValName argLValName = new TokenLValName (arg.name, ctorDeclFunc.argDecl.varDict);
-                                                                           // pass arg of that name to $objptr.$ctor()
-                argLValName.nextToken     = callCtorRVal.args;             // link to list of args passed to $objptr.$ctor()
-                callCtorRVal.args         = argLValName;
-            }
-
-            /*
-             * Set up a funky call to the constructor for the code body.
-             * This will let code generator know there is some craziness.
-             * See GenerateStmtNewobj().
-             *
-             * This is in essence:
-             *    {
-             *        classname $objptr = newobj (classname);
-             *        $objptr.$ctor (...);
-             *        return $objptr;
-             *    }
-             */
-            TokenStmtNewobj newobjStmtBody = new TokenStmtNewobj (ctorDeclFunc);
-            newobjStmtBody.objptrVar       = objptrVar;
-            newobjStmtBody.rValCall        = callCtorRVal;
-            TokenStmtBlock newobjBody      = new TokenStmtBlock (ctorDeclFunc);
-            newobjBody.statements          = newobjStmtBody;
-
-            /*
-             * Link that code as the body of the function.
-             */
-            newobjDeclFunc.body = newobjBody;
-
-            /*
-             * Say the function calls '$objptr.$ctor(arglist)' so we will inherit ctor's triviality.
-             */
-            newobjDeclFunc.unknownTrivialityCalls.AddLast (callCtorRVal);
-            return newobjDeclFunc;
-        }
-
-        private class TokenStmtNewobj : TokenStmt {
-            public TokenDeclVar objptrVar;
-            public TokenRValCall rValCall;
-            public TokenStmtNewobj (Token original) : base (original) { }
-        }
-
-        /**
-         * @brief Output function body (either event handler or script-defined method).
-         */
-        private void GenerateFuncBody ()
-        {
-            /*
-             * We want to know if the function's code is trivial, ie,
-             * if it doesn't have anything that might be an infinite 
-             * loop and that is doesn't call anything that might have 
-             * an infinite loop.  If it is, we don't need any CheckRun()
-             * stuff or any of the frame save/restore stuff.
-             */
-            bool isTrivial = curDeclFunc.IsFuncTrivial (this);
-
-            /*
-             * Clear list of all call labels.
-             * A call label is inserted just before every call that can possibly
-             * call CheckRun(), including any direct calls to CheckRun().
-             * Then, when restoring stack, we can just switch to this label to
-             * resume at the correct spot.
-             */
-            actCallLabels.Clear ();
-            allCallLabels.Clear ();
-            openCallLabel = null;
-
-            /*
-             * Alloc stack space for local vars.
-             */
-            AllocLocalVarStackSpace ();
-
-            /*
-             * Any return statements inside function body jump to this label
-             * after putting return value in __retval.
-             */
-            retLabel = ilGen.DefineLabel ("__retlbl");
-            retValue = null;
-            if (!(curDeclFunc.retType is TokenTypeVoid)) {
-                retValue = ilGen.DeclareLocal (curDeclFunc.retType.ToSysType (), "__retval");
-            }
-
-            /*
-             * Output:
-             *    int __mainCallNo = -1;
-             *    try {
-             *        if (instance.callMode != CallMode_NORMAL) goto __cmRestore;
-             */
-            actCallNo = null;
-            ScriptMyLabel cmRestore = null;
-            if (!isTrivial) {
-                actCallNo = ilGen.DeclareLocal (typeof (int), "__mainCallNo");
-                SetCallNo (curDeclFunc, actCallNo, -1);
-                cmRestore = ilGen.DefineLabel ("__cmRestore");
-                ilGen.BeginExceptionBlock ();
-                PushXMRInst ();
-                ilGen.Emit (curDeclFunc, OpCodes.Ldfld, ScriptCodeGen.callModeFieldInfo);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_NORMAL);
-                ilGen.Emit (curDeclFunc, OpCodes.Bne_Un, cmRestore);
-            }
-
-            /*
-             * Splice in the code optimizer for the body of the function.
-             */
-            ScriptCollector collector = new ScriptCollector ((ScriptObjWriter)ilGen);
-            _ilGen = collector;
-
-            /*
-             * If this is the default state_entry() handler, output code to set all global
-             * variables to their initial values.  Note that every script must have a
-             * default state_entry() handler, we provide one if the script doesn't explicitly
-             * define one.
-             */
-            string methname = ilGen.methName;
-            if (methname == "default state_entry") {
-
-                // if (!doGblInit) goto skipGblInit;
-                ScriptMyLabel skipGblInitLabel = ilGen.DefineLabel ("__skipGblInit");
-                PushXMRInst ();                                  // instance
-                ilGen.Emit (curDeclFunc, OpCodes.Ldfld, doGblInitFieldInfo);  // instance.doGblInit
-                ilGen.Emit (curDeclFunc, OpCodes.Brfalse, skipGblInitLabel);
-
-                // $globalvarinit();
-                TokenDeclVar gviFunc = tokenScript.globalVarInit;
-                if (gviFunc.body.statements != null) {
-                    gviFunc.location.CallPre  (this, gviFunc);
-                    gviFunc.location.CallPost (this, gviFunc);
-                }
-
-                // various $staticfieldinit();
-                foreach (TokenDeclSDType sdType in tokenScript.sdSrcTypesValues) {
-                    if (sdType is TokenDeclSDTypeClass) {
-                        TokenDeclVar sfiFunc = ((TokenDeclSDTypeClass)sdType).staticFieldInit;
-                        if ((sfiFunc != null) && (sfiFunc.body.statements != null)) {
-                            sfiFunc.location.CallPre  (this, sfiFunc);
-                            sfiFunc.location.CallPost (this, sfiFunc);
-                        }
-                    }
-                }
-
-                // doGblInit = 0;
-                PushXMRInst ();                                  // instance
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4_0);
-                ilGen.Emit (curDeclFunc, OpCodes.Stfld, doGblInitFieldInfo);  // instance.doGblInit
-
-                //skipGblInit:
-                ilGen.MarkLabel (skipGblInitLabel);
-            }
-
-            /*
-             * If this is a script-defined type constructor, call the base constructor and call
-             * this class's $instfieldinit() method to initialize instance fields.
-             */
-            if ((curDeclFunc.sdtClass != null) && curDeclFunc.funcNameSig.val.StartsWith ("$ctor(")) {
-                if (curDeclFunc.baseCtorCall != null) {
-                    GenerateFromRValCall (curDeclFunc.baseCtorCall);
-                }
-                TokenDeclVar ifiFunc = ((TokenDeclSDTypeClass)curDeclFunc.sdtClass).instFieldInit;
-                if (ifiFunc.body.statements != null) {
-                    CompValu thisCompValu = new CompValuArg (ifiFunc.sdtClass.MakeRefToken (ifiFunc), 0);
-                    CompValu ifiFuncLocn  = new CompValuInstMember (ifiFunc, thisCompValu, true);
-                    ifiFuncLocn.CallPre  (this, ifiFunc);
-                    ifiFuncLocn.CallPost (this, ifiFunc);
-                }
-            }
-
-            /*
-             * See if time to suspend in case they are doing a loop with recursion.
-             */
-            if (!isTrivial) EmitCallCheckRun (curDeclFunc, true);
-
-            /*
-             * Output code body.
-             */
-            GenerateStmtBlock (curDeclFunc.body);
-
-            /*
-             * If code falls through to this point, means they are missing 
-             * a return statement.  And that is legal only if the function 
-             * returns 'void'.
-             */
-            if (mightGetHere) {
-                if (!(curDeclFunc.retType is TokenTypeVoid)) {
-                    ErrorMsg (curDeclFunc.body, "missing final return statement");
-                }
-                ilGen.Emit (curDeclFunc, OpCodes.Leave, retLabel);
-            }
-
-            /*
-             * End of the code to be optimized.
-             * Do optimizations then write it all out to object file.
-             * After this, all code gets written directly to object file.
-             * Optimization must be completed before we scan the allCallLabels
-             * list below to look for active locals and temps.
-             */
-            collector.Optimize ();
-            _ilGen = collector.WriteOutAll ();
-            collector = null;
-
-            /*
-             * Output code to restore stack frame from stream.
-             * It jumps back to the call labels within the function body.
-             */
-            List<ScriptMyLocal> activeTemps = null;
-            if (!isTrivial) {
-
-                /*
-                 * Build list of locals and temps active at all the call labels.
-                 */
-                activeTemps = new List<ScriptMyLocal> ();
-                foreach (CallLabel cl in allCallLabels) {
-                    foreach (ScriptMyLocal lcl in cl.callLabel.whereAmI.localsReadBeforeWritten) {
-                        if (!activeTemps.Contains (lcl)) {
-                            activeTemps.Add (lcl);
-                        }
-                    }
-                }
-
-                /*
-                 * Output code to restore the args, locals and temps then jump to
-                 * the call label that we were interrupted at.
-                 */
-                ilGen.MarkLabel (cmRestore);
-                GenerateFrameRestoreCode (activeTemps);
-            }
-
-            /*
-             * Output epilog that saves stack frame state if CallMode_SAVE.
-             *
-             *   finally {
-             *      if (instance.callMode != CallMode_SAVE) goto __endFin;
-             *      GenerateFrameCaptureCode();
-             *   __endFin:
-             *   }
-             */
-            ScriptMyLabel endFin = null;
-            if (!isTrivial) {
-                ilGen.BeginFinallyBlock ();
-                endFin = ilGen.DefineLabel ("__endFin");
-                PushXMRInst ();
-                ilGen.Emit (curDeclFunc, OpCodes.Ldfld, callModeFieldInfo);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
-                ilGen.Emit (curDeclFunc, OpCodes.Bne_Un, endFin);
-                GenerateFrameCaptureCode (activeTemps);
-                ilGen.MarkLabel (endFin);
-                ilGen.Emit (curDeclFunc, OpCodes.Endfinally);
-                ilGen.EndExceptionBlock ();
-            }
-
-            /*
-             * Output the 'real' return opcode.
-             */
-            ilGen.MarkLabel (retLabel);
-            if (!(curDeclFunc.retType is TokenTypeVoid)) {
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, retValue);
-            }
-            ilGen.Emit (curDeclFunc, OpCodes.Ret);
-            retLabel = null;
-            retValue = null;
-
-            /*
-             * No more instructions for this method.
-             */
-            ((ScriptObjWriter)ilGen).EndMethod ();
-            _ilGen = null;
-
-            /*
-             * Not generating function code any more.
-             */
-            curBreakTarg = null;
-            curContTarg  = null;
-            curDeclFunc  = null;
-        }
-
-        /**
-         * @brief Allocate stack space for all local variables, regardless of
-         *        which { } statement block they are actually defined in.
-         */
-        private void AllocLocalVarStackSpace ()
-        {
-            foreach (TokenDeclVar localVar in curDeclFunc.localVars) {
-
-                /*
-                 * Skip all 'constant' vars as they were handled by the reducer.
-                 */
-                if (localVar.constant) continue;
-
-                /*
-                 * Get a stack location for the local variable.
-                 */
-                localVar.location = new CompValuLocalVar (localVar.type, localVar.name.val, this);
-            }
-        }
-
-        /**
-         * @brief Generate code to write all arguments and locals to the capture stack frame.
-         *        This includes temp variables.
-         *        We only need to save what is active at the point of callLabels through because 
-         *        those are the only points we will jump to on restore.  This saves us from saving 
-         *        all the little temp vars we create.
-         * @param activeTemps = list of locals and temps that we care about, ie, which
-         *                      ones get restored by GenerateFrameRestoreCode().
-         */
-        private void GenerateFrameCaptureCode (List<ScriptMyLocal> activeTemps)
-        {
-            /*
-             * Compute total number of slots we need to save stuff.
-             * Assume we need to save all call arguments.
-             */
-            int nSaves = curDeclFunc.argDecl.vars.Length + activeTemps.Count;
-
-            /*
-             * Output code to allocate a stack frame object with an object array.
-             * This also pushes the stack frame object on the instance.stackFrames list.
-             * It returns a pointer to the object array it allocated.
-             */
-            PushXMRInst ();
-            ilGen.Emit (curDeclFunc, OpCodes.Ldstr, ilGen.methName);
-            GetCallNo (curDeclFunc, actCallNo);
-            ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, nSaves);
-            ilGen.Emit (curDeclFunc, OpCodes.Call, captureStackFrameMethodInfo);
-
-            if (DEBUG_STACKCAPRES) {
-                ilGen.Emit (curDeclFunc, OpCodes.Ldstr, ilGen.methName + "*: capture mainCallNo=");
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, actCallNo);
-                ilGen.Emit (curDeclFunc, OpCodes.Box, typeof (int));
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            /*
-             * Copy arg values to object array, boxing as needed.
-             */
-            int i = 0;
-            foreach (TokenDeclVar argVar in curDeclFunc.argDecl.varDict) {
-                ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, i);
-                argVar.location.PushVal (this, argVar.name, tokenTypeObj);
-                if (DEBUG_STACKCAPRES) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n    arg:" + argVar.name.val + "=");
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                    ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                }
-                ilGen.Emit (curDeclFunc, OpCodes.Stelem_Ref);
-                i ++;
-            }
-
-            /*
-             * Copy local and temp values to object array, boxing as needed.
-             */
-            foreach (ScriptMyLocal lcl in activeTemps) {
-                ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, i ++);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, lcl);
-                Type t = lcl.type;
-                if (t == typeof (HeapTrackerList)) {
-                    t = HeapTrackerList.GenPush (curDeclFunc, ilGen);
-                }
-                if (t == typeof (HeapTrackerObject)) {
-                    t = HeapTrackerObject.GenPush (curDeclFunc, ilGen);
-                }
-                if (t == typeof(HeapTrackerString)) {
-                    t = HeapTrackerString.GenPush (curDeclFunc, ilGen);
-                }
-                if (t.IsValueType) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Box, t);
-                }
-                if (DEBUG_STACKCAPRES) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n    lcl:" + lcl.name + "=");
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                    ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                }
-                ilGen.Emit (curDeclFunc, OpCodes.Stelem_Ref);
-            }
-            if (DEBUG_STACKCAPRES) {
-                ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n");
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            ilGen.Emit (curDeclFunc, OpCodes.Pop);
-        }
-
-        /**
-         * @brief Generate code to restore all arguments and locals from the restore stack frame.
-         *        This includes temp variables.
-         */
-        private void GenerateFrameRestoreCode (List<ScriptMyLocal> activeTemps)
-        {
-            ScriptMyLocal objArray = ilGen.DeclareLocal (typeof (object[]), "__restObjArray");
-
-            /*
-             * Output code to pop stack frame from instance.stackFrames.
-             * It returns a pointer to the object array that contains values to be restored.
-             */
-            PushXMRInst ();
-            ilGen.Emit (curDeclFunc, OpCodes.Ldstr, ilGen.methName);
-            ilGen.Emit (curDeclFunc, OpCodes.Ldloca, actCallNo);  // __mainCallNo
-            ilGen.Emit (curDeclFunc, OpCodes.Call, restoreStackFrameMethodInfo);
-            ilGen.Emit (curDeclFunc, OpCodes.Stloc, objArray);
-            if (DEBUG_STACKCAPRES) {
-                ilGen.Emit (curDeclFunc, OpCodes.Ldstr, ilGen.methName + "*: restore mainCallNo=");
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, actCallNo);
-                ilGen.Emit (curDeclFunc, OpCodes.Box, typeof (int));
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            /*
-             * Restore argument values from object array, unboxing as needed.
-             * Although the caller has restored them to what it called us with, it's possible that this 
-             * function has modified them since, so we need to do our own restore.
-             */
-            int i = 0;
-            foreach (TokenDeclVar argVar in curDeclFunc.argDecl.varDict) {
-                CompValu argLoc = argVar.location;
-                argLoc.PopPre (this, argVar.name);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, objArray);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, i);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldelem_Ref);
-                if (DEBUG_STACKCAPRES) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n    arg:" + argVar.name.val + "=");
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                    ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                }
-                TypeCast.CastTopOfStack (this, argVar.name, tokenTypeObj, argLoc.type, true);
-                argLoc.PopPost (this, argVar.name);
-                i ++;
-            }
-
-            /*
-             * Restore local and temp values from object array, unboxing as needed.
-             */
-            foreach (ScriptMyLocal lcl in activeTemps) {
-                Type t = lcl.type;
-                Type u = t;
-                if (t == typeof (HeapTrackerList))   u = typeof (LSL_List);
-                if (t == typeof (HeapTrackerObject)) u = typeof (object);
-                if (t == typeof (HeapTrackerString)) u = typeof (string);
-                if (u != t) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Ldloc, lcl);
-                }
-                ilGen.Emit (curDeclFunc, OpCodes.Ldloc, objArray);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldc_I4, i ++);
-                ilGen.Emit (curDeclFunc, OpCodes.Ldelem_Ref);
-                if (DEBUG_STACKCAPRES) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n    lcl:" + lcl.name + "=");
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                    ilGen.Emit (curDeclFunc, OpCodes.Dup);
-                    ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-                }
-                if (u.IsValueType) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Unbox_Any, u);
-                } else if (u != typeof (object)) {
-                    ilGen.Emit (curDeclFunc, OpCodes.Castclass, u);
-                }
-                if (u != t) {
-                    if (t == typeof (HeapTrackerList))   HeapTrackerList.GenPop   (curDeclFunc, ilGen);
-                    if (t == typeof (HeapTrackerObject)) HeapTrackerObject.GenPop (curDeclFunc, ilGen);
-                    if (t == typeof (HeapTrackerString)) HeapTrackerString.GenPop (curDeclFunc, ilGen);
-                } else {
-                    ilGen.Emit (curDeclFunc, OpCodes.Stloc, lcl);
-                }
-            }
-            if (DEBUG_STACKCAPRES) {
-                ilGen.Emit (curDeclFunc, OpCodes.Ldstr, "\n");
-                ilGen.Emit (curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            OutputCallNoSwitchStmt ();
-        }
-
-        /**
-         * @brief Output a switch statement with a case for each possible 
-         *        value of whatever callNo is currently active, either 
-         *        __mainCallNo or one of the try/catch/finally's callNos.
-         *
-         *   switch (callNo) {
-         *      case 0: goto __call_0;
-         *      case 1: goto __call_1;
-         *      ...
-         *   }
-         *   throw new ScriptBadCallNoException (callNo);
-         */
-        private void OutputCallNoSwitchStmt ()
-        {
-            ScriptMyLabel[] callLabels = new ScriptMyLabel[actCallLabels.Count];
-            foreach (CallLabel cl in actCallLabels) {
-                callLabels[cl.index] = cl.callLabel;
-            }
-            GetCallNo (curDeclFunc, actCallNo);
-            ilGen.Emit (curDeclFunc, OpCodes.Switch, callLabels);
-
-            GetCallNo (curDeclFunc, actCallNo);
-            ilGen.Emit (curDeclFunc, OpCodes.Newobj, scriptBadCallNoExceptionConstructorInfo);
-            ilGen.Emit (curDeclFunc, OpCodes.Throw);
-        }
-
-        /**
-         * @brief There is one of these per call that can possibly call CheckRun(),
-         *        including direct calls to CheckRun().
-         *        They mark points that the stack capture/restore code will save & restore to.
-         *        All object-code level local vars active at the call label's point will 
-         *        be saved & restored.
-         *
-         *            callNo = 5;
-         *        __call_5:
-         *            push call arguments from temps
-         *            call SomethingThatCallsCheckRun()
-         *
-         *        If SomethingThatCallsCheckRun() actually calls CheckRun(), our restore code
-         *        will restore our args, locals & temps, then jump to __call_5, which will then 
-         *        call SomethingThatCallsCheckRun() again, which will restore its stuff likewise.
-         *        When eventually the actual CheckRun() call is restored, it will turn off restore 
-         *        mode (by changing callMode from CallMode_RESTORE to CallMode_NORMAL) and return, 
-         *        allowing the code to run normally from that point.
-         */
-        public class CallLabel {
-            public int           index;       // sequential integer, starting at 0, within actCallLabels
-                                              // - used for the switch statement
-            public ScriptMyLabel callLabel;   // the actual label token
-
-            public CallLabel (ScriptCodeGen scg, Token errorAt)
-            {
-                if (scg.openCallLabel != null) throw new Exception ("call label already open");
-
-                if (!scg.curDeclFunc.IsFuncTrivial (scg)) {
-                    this.index = scg.actCallLabels.Count;
-                    string name = "__call_" + index + "_" + scg.allCallLabels.Count;
-
-                    /*
-                     * Make sure eval stack is empty because the frame capture/restore 
-                     * code expects such (restore switch stmt has an empty stack).
-                     */
-                    int depth = ((ScriptCollector)scg.ilGen).stackDepth.Count;
-                    if (depth > 0) {
-                        // maybe need to call Trivialize()
-                        throw new Exception ("call label stack depth " + depth + " at " + errorAt.SrcLoc);
-                    }
-
-                    /*
-                     * Eval stack is empty so the restore code can handle it.
-                     */
-                    this.index = scg.actCallLabels.Count;
-                    scg.actCallLabels.AddLast (this);
-                    scg.allCallLabels.AddLast (this);
-                    this.callLabel = scg.ilGen.DefineLabel (name);
-                    scg.SetCallNo (errorAt, scg.actCallNo, this.index);
-                    scg.ilGen.MarkLabel (this.callLabel);
-                }
-
-                scg.openCallLabel = this;
-            }
-        };
-
-        /**
-         * @brief generate code for an arbitrary statement.
-         */
-        private void GenerateStmt (TokenStmt stmt)
-        {
-            errorMessageToken = stmt;
-            if (stmt is TokenDeclVar)       { GenerateDeclVar       ((TokenDeclVar)stmt);       return; }
-            if (stmt is TokenStmtBlock)     { GenerateStmtBlock     ((TokenStmtBlock)stmt);     return; }
-            if (stmt is TokenStmtBreak)     { GenerateStmtBreak     ((TokenStmtBreak)stmt);     return; }
-            if (stmt is TokenStmtCont)      { GenerateStmtCont      ((TokenStmtCont)stmt);      return; }
-            if (stmt is TokenStmtDo)        { GenerateStmtDo        ((TokenStmtDo)stmt);        return; }
-            if (stmt is TokenStmtFor)       { GenerateStmtFor       ((TokenStmtFor)stmt);       return; }
-            if (stmt is TokenStmtForEach)   { GenerateStmtForEach   ((TokenStmtForEach)stmt);   return; }
-            if (stmt is TokenStmtIf)        { GenerateStmtIf        ((TokenStmtIf)stmt);        return; }
-            if (stmt is TokenStmtJump)      { GenerateStmtJump      ((TokenStmtJump)stmt);      return; }
-            if (stmt is TokenStmtLabel)     { GenerateStmtLabel     ((TokenStmtLabel)stmt);     return; }
-            if (stmt is TokenStmtNewobj)    { GenerateStmtNewobj    ((TokenStmtNewobj)stmt);    return; }
-            if (stmt is TokenStmtNull)      {                                                   return; }
-            if (stmt is TokenStmtRet)       { GenerateStmtRet       ((TokenStmtRet)stmt);       return; }
-            if (stmt is TokenStmtRVal)      { GenerateStmtRVal      ((TokenStmtRVal)stmt);      return; }
-            if (stmt is TokenStmtState)     { GenerateStmtState     ((TokenStmtState)stmt);     return; }
-            if (stmt is TokenStmtSwitch)    { GenerateStmtSwitch    ((TokenStmtSwitch)stmt);    return; }
-            if (stmt is TokenStmtThrow)     { GenerateStmtThrow     ((TokenStmtThrow)stmt);     return; }
-            if (stmt is TokenStmtTry)       { GenerateStmtTry       ((TokenStmtTry)stmt);       return; }
-            if (stmt is TokenStmtVarIniDef) { GenerateStmtVarIniDef ((TokenStmtVarIniDef)stmt); return; }
-            if (stmt is TokenStmtWhile)     { GenerateStmtWhile     ((TokenStmtWhile)stmt);     return; }
-            throw new Exception ("unknown TokenStmt type " + stmt.GetType ().ToString ());
-        }
-
-        /**
-         * @brief generate statement block (ie, with braces)
-         */
-        private void GenerateStmtBlock (TokenStmtBlock stmtBlock)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Push new current statement block pointer for anyone who cares.
-             */
-            TokenStmtBlock oldStmtBlock = curStmtBlock;
-            curStmtBlock = stmtBlock;
-
-            /*
-             * Output the statements that make up the block.
-             */
-            for (Token t = stmtBlock.statements; t != null; t = t.nextToken) {
-                GenerateStmt ((TokenStmt)t);
-            }
-
-            /*
-             * Pop the current statement block.
-             */
-            curStmtBlock = oldStmtBlock;
-        }
-
-        /**
-         * @brief output code for a 'break' statement
-         */
-        private void GenerateStmtBreak (TokenStmtBreak breakStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Make sure we are in a breakable situation.
-             */
-            if (curBreakTarg == null) {
-                ErrorMsg (breakStmt, "not in a breakable situation");
-                return;
-            }
-
-            /*
-             * Tell anyone who cares that the break target was actually used.
-             */
-            curBreakTarg.used = true;
-
-            /*
-             * Output the instructions.
-             */
-            EmitJumpCode (curBreakTarg.label, curBreakTarg.block, breakStmt);
-        }
-
-        /**
-         * @brief output code for a 'continue' statement
-         */
-        private void GenerateStmtCont (TokenStmtCont contStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Make sure we are in a contable situation.
-             */
-            if (curContTarg == null) {
-                ErrorMsg (contStmt, "not in a continueable situation");
-                return;
-            }
-
-            /*
-             * Tell anyone who cares that the continue target was actually used.
-             */
-            curContTarg.used = true;
-
-            /*
-             * Output the instructions.
-             */
-            EmitJumpCode (curContTarg.label, curContTarg.block, contStmt);
-        }
-
-        /**
-         * @brief output code for a 'do' statement
-         */
-        private void GenerateStmtDo (TokenStmtDo doStmt)
-        {
-            if (!mightGetHere) return;
-
-            BreakContTarg oldBreakTarg = curBreakTarg;
-            BreakContTarg oldContTarg  = curContTarg;
-            ScriptMyLabel loopLabel    = ilGen.DefineLabel ("doloop_" + doStmt.Unique);
-
-            curBreakTarg = new BreakContTarg (this, "dobreak_" + doStmt.Unique);
-            curContTarg  = new BreakContTarg (this, "docont_"  + doStmt.Unique);
-
-            ilGen.MarkLabel (loopLabel);
-            GenerateStmt (doStmt.bodyStmt);
-            if (curContTarg.used) {
-                ilGen.MarkLabel (curContTarg.label);
-                mightGetHere = true;
-            }
-
-            if (mightGetHere) {
-                EmitCallCheckRun (doStmt, false);
-                CompValu testRVal = GenerateFromRVal (doStmt.testRVal);
-                if (IsConstBoolExprTrue (testRVal)) {
-
-                    /*
-                     * Unconditional looping, unconditional branch and
-                     * say we never fall through to next statement.
-                     */
-                    ilGen.Emit (doStmt, OpCodes.Br, loopLabel);
-                    mightGetHere = false;
-                } else {
-
-                    /*
-                     * Conditional looping, test and brach back to top of loop.
-                     */
-                    testRVal.PushVal (this, doStmt.testRVal, tokenTypeBool);
-                    ilGen.Emit (doStmt, OpCodes.Brtrue, loopLabel);
-                }
-            }
-
-            /*
-             * If 'break' statement was used, output target label.
-             * And assume that since a 'break' statement was used, it's possible for the code to get here.
-             */
-            if (curBreakTarg.used) {
-                ilGen.MarkLabel (curBreakTarg.label);
-                mightGetHere = true;
-            }
-
-            curBreakTarg = oldBreakTarg;
-            curContTarg  = oldContTarg;
-        }
-
-        /**
-         * @brief output code for a 'for' statement
-         */
-        private void GenerateStmtFor (TokenStmtFor forStmt)
-        {
-            if (!mightGetHere) return;
-
-            BreakContTarg oldBreakTarg = curBreakTarg;
-            BreakContTarg oldContTarg  = curContTarg;
-            ScriptMyLabel loopLabel    = ilGen.DefineLabel ("forloop_" + forStmt.Unique);
-
-            curBreakTarg = new BreakContTarg (this, "forbreak_" + forStmt.Unique);
-            curContTarg  = new BreakContTarg (this, "forcont_"  + forStmt.Unique);
-
-            if (forStmt.initStmt != null) {
-                GenerateStmt (forStmt.initStmt);
-            }
-            ilGen.MarkLabel (loopLabel);
-
-            /*
-             * See if we have a test expression that is other than a constant TRUE.
-             * If so, test it and conditionally branch to end if false.
-             */
-            if (forStmt.testRVal != null) {
-                CompValu testRVal = GenerateFromRVal (forStmt.testRVal);
-                if (!IsConstBoolExprTrue (testRVal)) {
-                    testRVal.PushVal (this, forStmt.testRVal, tokenTypeBool);
-                    ilGen.Emit (forStmt, OpCodes.Brfalse, curBreakTarg.label);
-                    curBreakTarg.used = true;
-                }
-            }
-
-            /*
-             * Output loop body.
-             */
-            GenerateStmt (forStmt.bodyStmt);
-
-            /*
-             * Here's where a 'continue' statement jumps to.
-             */
-            if (curContTarg.used) {
-                ilGen.MarkLabel (curContTarg.label);
-                mightGetHere = true;
-            }
-
-            if (mightGetHere) {
-
-                /*
-                 * After checking for excessive CPU time, output increment statement, if any.
-                 */
-                EmitCallCheckRun (forStmt, false);
-                if (forStmt.incrRVal != null) {
-                    GenerateFromRVal (forStmt.incrRVal);
-                }
-
-                /*
-                 * Unconditional branch back to beginning of loop.
-                 */
-                ilGen.Emit (forStmt, OpCodes.Br, loopLabel);
-            }
-
-            /*
-             * If test needs label, output label for it to jump to.
-             * Otherwise, clear mightGetHere as we know loop never
-             * falls out the bottom.
-             */
-            mightGetHere = curBreakTarg.used;
-            if (mightGetHere) {
-                ilGen.MarkLabel (curBreakTarg.label);
-            }
-
-            curBreakTarg = oldBreakTarg;
-            curContTarg  = oldContTarg;
-        }
-
-        private void GenerateStmtForEach (TokenStmtForEach forEachStmt)
-        {
-            if (!mightGetHere) return;
-
-            BreakContTarg oldBreakTarg = curBreakTarg;
-            BreakContTarg oldContTarg  = curContTarg;
-            CompValu      keyLVal      = null;
-            CompValu      valLVal      = null;
-            CompValu      arrayRVal    = GenerateFromRVal (forEachStmt.arrayRVal);
-
-            if (forEachStmt.keyLVal != null) {
-                keyLVal = GenerateFromLVal (forEachStmt.keyLVal);
-                if (!(keyLVal.type is TokenTypeObject)) {
-                    ErrorMsg (forEachStmt.arrayRVal, "must be object");
-                }
-            }
-            if (forEachStmt.valLVal != null) {
-                valLVal = GenerateFromLVal (forEachStmt.valLVal);
-                if (!(valLVal.type is TokenTypeObject)) {
-                    ErrorMsg (forEachStmt.arrayRVal, "must be object");
-                }
-            }
-            if (!(arrayRVal.type is TokenTypeArray)) {
-                ErrorMsg (forEachStmt.arrayRVal, "must be an array");
-            }
-
-            curBreakTarg = new BreakContTarg (this, "foreachbreak_" + forEachStmt.Unique);
-            curContTarg  = new BreakContTarg (this, "foreachcont_"  + forEachStmt.Unique);
-
-            CompValuTemp indexVar = new CompValuTemp (new TokenTypeInt (forEachStmt), this);
-            ScriptMyLabel loopLabel = ilGen.DefineLabel ("foreachloop_" + forEachStmt.Unique);
-
-            // indexVar = 0
-            ilGen.Emit (forEachStmt, OpCodes.Ldc_I4_0);
-            indexVar.Pop (this, forEachStmt);
-
-            ilGen.MarkLabel (loopLabel);
-
-            // key = array.__pub_index (indexVar);
-            // if (key == null) goto curBreakTarg;
-            if (keyLVal != null) {
-                keyLVal.PopPre (this, forEachStmt.keyLVal);
-                arrayRVal.PushVal (this, forEachStmt.arrayRVal);
-                indexVar.PushVal (this, forEachStmt);
-                ilGen.Emit (forEachStmt, OpCodes.Call, xmrArrPubIndexMethod);
-                keyLVal.PopPost (this, forEachStmt.keyLVal);
-                keyLVal.PushVal (this, forEachStmt.keyLVal);
-                ilGen.Emit (forEachStmt, OpCodes.Brfalse, curBreakTarg.label);
-                curBreakTarg.used = true;
-            }
-
-            // val = array._pub_value (indexVar);
-            // if (val == null) goto curBreakTarg;
-            if (valLVal != null) {
-                valLVal.PopPre (this, forEachStmt.valLVal);
-                arrayRVal.PushVal (this, forEachStmt.arrayRVal);
-                indexVar.PushVal (this, forEachStmt);
-                ilGen.Emit (forEachStmt, OpCodes.Call, xmrArrPubValueMethod);
-                valLVal.PopPost (this, forEachStmt.valLVal);
-                if (keyLVal == null) {
-                    valLVal.PushVal (this, forEachStmt.valLVal);
-                    ilGen.Emit (forEachStmt, OpCodes.Brfalse, curBreakTarg.label);
-                    curBreakTarg.used = true;
-                }
-            }
-
-            // indexVar ++;
-            indexVar.PushVal (this, forEachStmt);
-            ilGen.Emit (forEachStmt, OpCodes.Ldc_I4_1);
-            ilGen.Emit (forEachStmt, OpCodes.Add);
-            indexVar.Pop (this, forEachStmt);
-
-            // body statement
-            GenerateStmt (forEachStmt.bodyStmt);
-
-            // continue label
-            if (curContTarg.used) {
-                ilGen.MarkLabel (curContTarg.label);
-                mightGetHere = true;
-            }
-
-            // call CheckRun()
-            if (mightGetHere) {
-                EmitCallCheckRun (forEachStmt, false);
-                ilGen.Emit (forEachStmt, OpCodes.Br, loopLabel);
-            }
-
-            // break label
-            ilGen.MarkLabel (curBreakTarg.label);
-            mightGetHere = true;
-
-            curBreakTarg = oldBreakTarg;
-            curContTarg  = oldContTarg;
-        }
-
-        /**
-         * @brief output code for an 'if' statement
-         * Braces are necessary because what may be one statement for trueStmt or elseStmt in
-         * the script may translate to more than one statement in the resultant C# code.
-         */
-        private void GenerateStmtIf (TokenStmtIf ifStmt)
-        {
-            if (!mightGetHere) return;
-
-            bool constVal;
-
-            /*
-             * Test condition and see if constant test expression.
-             */
-            CompValu testRVal = GenerateFromRVal (ifStmt.testRVal);
-            if (IsConstBoolExpr (testRVal, out constVal)) {
-
-                /*
-                 * Constant, output just either the true or else part.
-                 */
-                if (constVal) {
-                    GenerateStmt (ifStmt.trueStmt);
-                } else if (ifStmt.elseStmt != null) {
-                    GenerateStmt (ifStmt.elseStmt);
-                }
-            } else if (ifStmt.elseStmt == null) {
-
-                /*
-                 * This is an 'if' statement without an 'else' clause.
-                 */
-                testRVal.PushVal (this, ifStmt.testRVal, tokenTypeBool);
-                ScriptMyLabel doneLabel = ilGen.DefineLabel ("ifdone_" + ifStmt.Unique);
-                ilGen.Emit (ifStmt, OpCodes.Brfalse, doneLabel);  // brfalse doneLabel
-                GenerateStmt (ifStmt.trueStmt);                   // generate true body code
-                ilGen.MarkLabel (doneLabel);
-                mightGetHere = true;                              // there's always a possibility of getting here
-            } else {
-
-                /*
-                 * This is an 'if' statement with an 'else' clause.
-                 */
-                testRVal.PushVal (this, ifStmt.testRVal, tokenTypeBool);
-                ScriptMyLabel elseLabel = ilGen.DefineLabel ("ifelse_" + ifStmt.Unique);
-                ilGen.Emit (ifStmt, OpCodes.Brfalse, elseLabel);  // brfalse elseLabel
-                GenerateStmt (ifStmt.trueStmt);                   // generate true body code
-                bool trueMightGetHere = mightGetHere;             // save whether or not true falls through
-                ScriptMyLabel doneLabel = ilGen.DefineLabel ("ifdone_" + ifStmt.Unique);
-                ilGen.Emit (ifStmt, OpCodes.Br, doneLabel);       // branch to done
-                ilGen.MarkLabel (elseLabel);                      // beginning of else code
-                mightGetHere = true;                              // the top of the else might be executed
-                GenerateStmt (ifStmt.elseStmt);                   // output else code
-                ilGen.MarkLabel (doneLabel);                      // where end of true clause code branches to
-                mightGetHere |= trueMightGetHere;                 // gets this far if either true or else falls through
-            }
-        }
-
-        /**
-         * @brief output code for a 'jump' statement
-         */
-        private void GenerateStmtJump (TokenStmtJump jumpStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Make sure the target label is defined somewhere in the function.
-             */
-            TokenStmtLabel stmtLabel;
-            if (!curDeclFunc.labels.TryGetValue (jumpStmt.label.val, out stmtLabel)) {
-                ErrorMsg (jumpStmt, "undefined label " + jumpStmt.label.val);
-                return;
-            }
-            if (!stmtLabel.labelTagged) {
-                stmtLabel.labelStruct = ilGen.DefineLabel ("jump_" + stmtLabel.name.val);
-                stmtLabel.labelTagged = true;
-            }
-
-            /*
-             * Emit instructions to do the jump.
-             */
-            EmitJumpCode (stmtLabel.labelStruct, stmtLabel.block, jumpStmt);
-        }
-
-        /**
-         * @brief Emit code to jump to a label
-         * @param target = label being jumped to
-         * @param targetsBlock = { ... } the label is defined in
-         */
-        private void EmitJumpCode (ScriptMyLabel target, TokenStmtBlock targetsBlock, Token errorAt)
-        {
-            /*
-             * Jumps never fall through.
-             */
-            mightGetHere = false;
-
-            /*
-             * Find which block the target label is in.  Must be in this or an outer block,
-             * no laterals allowed.  And if we exit a try/catch block, use Leave instead of Br.
-             *
-             *    jump lateral;
-             *    {
-             *        @lateral;
-             *    }
-             */
-            bool useLeave = false;
-            TokenStmtBlock stmtBlock;
-            Stack<TokenStmtTry> finallyBlocksCalled = new Stack<TokenStmtTry> ();
-            for (stmtBlock = curStmtBlock; stmtBlock != targetsBlock; stmtBlock = stmtBlock.outerStmtBlock) {
-                if (stmtBlock == null) {
-                    ErrorMsg (errorAt, "no lateral jumps allowed");
-                    return;
-                }
-                if (stmtBlock.isFinally) {
-                    ErrorMsg (errorAt, "cannot jump out of finally");
-                    return;
-                }
-                if (stmtBlock.isTry || stmtBlock.isCatch) useLeave = true;
-                if ((stmtBlock.tryStmt != null) && (stmtBlock.tryStmt.finallyStmt != null)) {
-                    finallyBlocksCalled.Push (stmtBlock.tryStmt);
-                }
-            }
-
-            /*
-             * If popping through more than one finally block, we have to break it down for the stack 
-             * capture and restore code, one finally block at a time.
-             *
-             *     try {
-             *         try {
-             *             try {
-             *                 jump exit;
-             *             } finally {
-             *                 llOwnerSay ("exiting inner");
-             *             }
-             *         } finally {
-             *             llOwnerSay ("exiting middle");
-             *         }
-             *     } finally {
-             *         llOwnerSay ("exiting outer");
-             *     }
-             *   @exit;
-             *
-             *     try {
-             *         try {
-             *             try {
-             *                 jump intr2_exit;         <<< gets its own tryNo call label so inner try knows where to restore to
-             *             } finally {
-             *                 llOwnerSay ("exiting inner");
-             *             }
-             *             jump outtry2;
-             *           @intr2_exit; jump intr1_exit;  <<< gets its own tryNo call label so middle try knows where to restore to
-             *           @outtry2;
-             *         } finally {
-             *             llOwnerSay ("exiting middle");
-             *         }
-             *         jump outtry1;
-             *       @intr1_exit: jump exit;            <<< gets its own tryNo call label so outer try knows where to restore to
-             *       @outtry1;
-             *     } finally {
-             *         llOwnerSay ("exiting outer");
-             *     }
-             *   @exit;
-             */
-            int level = 0;
-            while (finallyBlocksCalled.Count > 1) {
-                TokenStmtTry finallyBlock = finallyBlocksCalled.Pop ();
-                string intername = "intr" + (++ level) + "_" + target.name;
-                IntermediateLeave iLeave;
-                if (!finallyBlock.iLeaves.TryGetValue (intername, out iLeave)) {
-                    iLeave = new IntermediateLeave ();
-                    iLeave.jumpIntoLabel = ilGen.DefineLabel (intername);
-                    iLeave.jumpAwayLabel = target;
-                    finallyBlock.iLeaves.Add (intername, iLeave);
-                }
-                target = iLeave.jumpIntoLabel;
-            }
-
-            /*
-             * Finally output the branch/leave opcode.
-             * If using Leave, prefix with a call label in case the corresponding finally block
-             * calls CheckRun() and that CheckRun() captures the stack, it will have a point to 
-             * restore to that will properly jump back into the finally block.
-             */
-            if (useLeave) {
-                new CallLabel (this, errorAt);
-                ilGen.Emit (errorAt, OpCodes.Leave, target);
-                openCallLabel = null;
-            } else {
-                ilGen.Emit (errorAt, OpCodes.Br, target);
-            }
-        }
-
-        /**
-         * @brief output code for a jump target label statement.
-         * If there are any backward jumps to the label, do a CheckRun() also.
-         */
-        private void GenerateStmtLabel (TokenStmtLabel labelStmt)
-        {
-            if (!labelStmt.labelTagged) {
-                labelStmt.labelStruct = ilGen.DefineLabel ("jump_" + labelStmt.name.val);
-                labelStmt.labelTagged = true;
-            }
-            ilGen.MarkLabel (labelStmt.labelStruct);
-            if (labelStmt.hasBkwdRefs) {
-                EmitCallCheckRun (labelStmt, false);
-            }
-
-            /*
-             * We are going to say that the label falls through.
-             * It would be nice if we could analyze all referencing
-             * goto's to see if all of them are not used but we are
-             * going to assume that if the script writer put a label
-             * somewhere, it is probably going to be used.
-             */
-            mightGetHere = true;
-        }
-
-        /**
-         * @brief Generate code for a script-defined type's <typename>.$new(<argsig>) method.
-         *        It is used to malloc the object and initialize it.
-         *        It is defined as a script-defined type static method, so the object level
-         *        method gets the XMRInstance pointer passed as arg 0, and the method is 
-         *        supposed to return the allocated and constructed XMRSDTypeClObj
-         *        object pointer.
-         */
-        private void GenerateStmtNewobj (TokenStmtNewobj newobjStmt)
-        {
-            /*
-             * First off, malloc a new empty XMRSDTypeClObj object
-             * then call the XMRSDTypeClObj()-level constructor.
-             * Store the result in local var $objptr.
-             */
-            newobjStmt.objptrVar.location.PopPre (this, newobjStmt);
-            ilGen.Emit (newobjStmt, OpCodes.Ldarg_0);
-            ilGen.Emit (newobjStmt, OpCodes.Ldc_I4, curDeclFunc.sdtClass.sdTypeIndex);
-            ilGen.Emit (newobjStmt, OpCodes.Newobj, sdtClassConstructorInfo);
-            newobjStmt.objptrVar.location.PopPost (this, newobjStmt);
-
-            /*
-             * Now call the script-level constructor.
-             * Pass the object pointer in $objptr as it's 'this' argument.
-             * The rest of the args are the script-visible args and are just copied from $new() call.
-             */
-            GenerateFromRValCall (newobjStmt.rValCall);
-
-            /*
-             * Put object pointer in retval so it gets returned to caller.
-             */
-            newobjStmt.objptrVar.location.PushVal (this, newobjStmt);
-            ilGen.Emit (newobjStmt, OpCodes.Stloc, retValue);
-
-            /*
-             * Exit the function like a return statement.
-             * And thus we don't fall through.
-             */
-            ilGen.Emit (newobjStmt, OpCodes.Leave, retLabel);
-            mightGetHere = false;
-        }
-
-        /**
-         * @brief output code for a return statement.
-         * @param retStmt = return statement token, including return value if any
-         */
-        private void GenerateStmtRet (TokenStmtRet retStmt)
-        {
-            if (!mightGetHere) return;
-
-            for (TokenStmtBlock stmtBlock = curStmtBlock; stmtBlock != null; stmtBlock = stmtBlock.outerStmtBlock) {
-                if (stmtBlock.isFinally) {
-                    ErrorMsg (retStmt, "cannot return out of finally");
-                    return;
-                }
-            }
-
-            if (curDeclFunc.retType is TokenTypeVoid) {
-                if (retStmt.rVal != null) {
-                    ErrorMsg (retStmt, "function returns void, no value allowed");
-                    return;
-                }
-            } else {
-                if (retStmt.rVal == null) {
-                    ErrorMsg (retStmt, "function requires return value type " + curDeclFunc.retType.ToString ());
-                    return;
-                }
-                CompValu rVal = GenerateFromRVal (retStmt.rVal);
-                rVal.PushVal (this, retStmt.rVal, curDeclFunc.retType);
-                ilGen.Emit (retStmt, OpCodes.Stloc, retValue);
-            }
-
-            /*
-             * Use a OpCodes.Leave instruction to break out of any try { } blocks.
-             * All Leave's inside script-defined try { } need call labels (see GenerateStmtTry()).
-             */
-            bool brokeOutOfTry = false;
-            for (TokenStmtBlock stmtBlock = curStmtBlock; stmtBlock != null; stmtBlock = stmtBlock.outerStmtBlock) {
-                if (stmtBlock.isTry) {
-                    brokeOutOfTry = true;
-                    break;
-                }
-            }
-            if (brokeOutOfTry) new CallLabel (this, retStmt);
-            ilGen.Emit (retStmt, OpCodes.Leave, retLabel);
-            if (brokeOutOfTry) openCallLabel = null;
-
-            /*
-             * 'return' statements never fall through.
-             */
-            mightGetHere = false;
-        }
-
-        /**
-         * @brief the statement is just an expression, most likely an assignment or a ++ or -- thing.
-         */
-        private void GenerateStmtRVal (TokenStmtRVal rValStmt)
-        {
-            if (!mightGetHere) return;
-
-            GenerateFromRVal (rValStmt.rVal);
-        }
-
-        /**
-         * @brief generate code for a 'state' statement that transitions state.
-         * It sets the new state by throwing a ScriptChangeStateException.
-         */
-        private void GenerateStmtState (TokenStmtState stateStmt)
-        {
-            if (!mightGetHere) return;
-
-            int index = 0;  // 'default' state
-
-            /*
-             * Set new state value by throwing an exception.
-             * These exceptions aren't catchable by script-level try { } catch { }.
-             */
-            if ((stateStmt.state != null) && !stateIndices.TryGetValue (stateStmt.state.val, out index)) {
-                // The moron XEngine compiles scripts that reference undefined states.
-                // So rather than produce a compile-time error, we'll throw an exception at runtime.
-                // ErrorMsg (stateStmt, "undefined state " + stateStmt.state.val);
-
-                // throw new UndefinedStateException (stateStmt.state.val);
-                ilGen.Emit (stateStmt, OpCodes.Ldstr, stateStmt.state.val);
-                ilGen.Emit (stateStmt, OpCodes.Newobj, scriptUndefinedStateExceptionConstructorInfo);
-            } else {
-                ilGen.Emit (stateStmt, OpCodes.Ldc_I4, index);  // new state's index
-                ilGen.Emit (stateStmt, OpCodes.Newobj, scriptChangeStateExceptionConstructorInfo);
-            }
-            ilGen.Emit (stateStmt, OpCodes.Throw);
-
-            /*
-             * 'state' statements never fall through.
-             */
-            mightGetHere = false;
-        }
-
-        /**
-         * @brief output code for a 'switch' statement
-         */
-        private void GenerateStmtSwitch (TokenStmtSwitch switchStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Output code to calculate index.
-             */
-            CompValu testRVal = GenerateFromRVal (switchStmt.testRVal);
-
-            /*
-             * Generate code based on string or integer index.
-             */
-            if ((testRVal.type is TokenTypeKey) || (testRVal.type is TokenTypeStr)) {
-                GenerateStmtSwitchStr (testRVal, switchStmt);
-            } else {
-                GenerateStmtSwitchInt (testRVal, switchStmt);
-            }
-        }
-
-        private void GenerateStmtSwitchInt (CompValu testRVal, TokenStmtSwitch switchStmt)
-        {
-            testRVal.PushVal (this, switchStmt.testRVal, tokenTypeInt);
-
-            BreakContTarg   oldBreakTarg = curBreakTarg;
-            ScriptMyLabel   defaultLabel = null;
-            TokenSwitchCase sortedCases  = null;
-            TokenSwitchCase defaultCase  = null;
-
-            curBreakTarg = new BreakContTarg (this, "switchbreak_" + switchStmt.Unique);
-
-            /*
-             * Build list of cases sorted by ascending values.
-             * There should not be any overlapping of values.
-             */
-            for (TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase) {
-                thisCase.label = ilGen.DefineLabel ("case_" + thisCase.Unique);
-
-                /*
-                 * The default case if any, goes in its own separate slot.
-                 */
-                if (thisCase.rVal1 == null) {
-                    if (defaultCase != null) {
-                        ErrorMsg (thisCase, "only one default case allowed");
-                        ErrorMsg (defaultCase, "...prior default case");
-                        return;
-                    }
-                    defaultCase  = thisCase;
-                    defaultLabel = thisCase.label;
-                    continue;
-                }
-
-                /*
-                 * Evaluate case operands, they must be compile-time integer constants.
-                 */
-                CompValu rVal = GenerateFromRVal (thisCase.rVal1);
-                if (!IsConstIntExpr (rVal, out thisCase.val1)) {
-                    ErrorMsg (thisCase.rVal1, "must be compile-time char or integer constant");
-                    return;
-                }
-                thisCase.val2 = thisCase.val1;
-                if (thisCase.rVal2 != null) {
-                    rVal = GenerateFromRVal (thisCase.rVal2);
-                    if (!IsConstIntExpr (rVal, out thisCase.val2)) {
-                        ErrorMsg (thisCase.rVal2, "must be compile-time char or integer constant");
-                        return;
-                    }
-                }
-                if (thisCase.val2 < thisCase.val1) {
-                    ErrorMsg (thisCase.rVal2, "must be .ge. first value for the case");
-                    return;
-                }
-
-                /*
-                 * Insert into list, sorted by value.
-                 * Note that both limits are inclusive.
-                 */
-                TokenSwitchCase lastCase = null;
-                TokenSwitchCase nextCase;
-                for (nextCase = sortedCases; nextCase != null; nextCase = nextCase.nextSortedCase) {
-                    if (nextCase.val1 >  thisCase.val2) break;
-                    if (nextCase.val2 >= thisCase.val1) {
-                        ErrorMsg (thisCase, "value used by previous case");
-                        ErrorMsg (nextCase, "...previous case");
-                        return;
-                    }
-                    lastCase = nextCase;
-                }
-                thisCase.nextSortedCase = nextCase;
-                if (lastCase == null) {
-                    sortedCases = thisCase;
-                } else {
-                    lastCase.nextSortedCase = thisCase;
-                }
-            }
-
-            if (defaultLabel == null) {
-                defaultLabel = ilGen.DefineLabel ("default_" + switchStmt.Unique);
-            }
-
-            /*
-             * Output code to jump to the case statement's labels based on integer index on stack.
-             * Note that each case still has the integer index on stack when jumped to.
-             */
-            int offset = 0;
-            for (TokenSwitchCase thisCase = sortedCases; thisCase != null;) {
-
-                /*
-                 * Scan through list of cases to find the maximum number of cases who's numvalues-to-case ratio
-                 * is from 0.5 to 2.0.  If such a group is found, use a CIL switch for them.  If not, just use a
-                 * compare-and-branch for the current case.
-                 */
-                int numCases  = 0;
-                int numFound  = 0;
-                int lowValue  = thisCase.val1;
-                int numValues = 0;
-                for (TokenSwitchCase scanCase = thisCase; scanCase != null; scanCase = scanCase.nextSortedCase) {
-                    int nVals = scanCase.val2 - thisCase.val1 + 1;
-                    double ratio = (double)nVals / (double)(++ numCases);
-                    if ((ratio >= 0.5) && (ratio <= 2.0)) {
-                        numFound  = numCases;
-                        numValues = nVals;
-                    }
-                }
-                if (numFound > 1) {
-
-                    /*
-                     * There is a group of case's, starting with thisCase, that fall within our criteria, ie, 
-                     * that have a nice density of meaningful jumps.
-                     *
-                     * So first generate an array of jumps to the default label (explicit or implicit).
-                     */
-                    ScriptMyLabel[] labels = new ScriptMyLabel[numValues];
-                    for (int i = 0; i < numValues; i ++) {
-                        labels[i] = defaultLabel;
-                    }
-
-                    /*
-                     * Next, for each case in that group, fill in the corresponding array entries to jump to
-                     * that case's label.
-                     */
-                    do {
-                        for (int i = thisCase.val1; i <= thisCase.val2; i ++) {
-                            labels[i-lowValue] = thisCase.label;
-                        }
-                        thisCase = thisCase.nextSortedCase;
-                    } while (-- numFound > 0);
-
-                    /*
-                     * Subtract the low value and do the computed jump.
-                     * The OpCodes.Switch falls through if out of range (unsigned compare).
-                     */
-                    if (offset != lowValue) {
-                        ilGen.Emit (switchStmt, OpCodes.Ldc_I4, lowValue - offset);
-                        ilGen.Emit (switchStmt, OpCodes.Sub);
-                        offset = lowValue;
-                    }
-                    ilGen.Emit (switchStmt, OpCodes.Dup);
-                    ilGen.Emit (switchStmt, OpCodes.Switch, labels);
-                } else {
-
-                    /*
-                     * It's not economical to do with a computed jump, so output a subtract/compare/branch
-                     * for thisCase.
-                     */
-                    if (lowValue == thisCase.val2) {
-                        ilGen.Emit (switchStmt, OpCodes.Dup);
-                        ilGen.Emit (switchStmt, OpCodes.Ldc_I4, lowValue - offset);
-                        ilGen.Emit (switchStmt, OpCodes.Beq, thisCase.label);
-                    } else {
-                        if (offset != lowValue) {
-                            ilGen.Emit (switchStmt, OpCodes.Ldc_I4, lowValue - offset);
-                            ilGen.Emit (switchStmt, OpCodes.Sub);
-                            offset = lowValue;
-                        }
-                        ilGen.Emit (switchStmt, OpCodes.Dup);
-                        ilGen.Emit (switchStmt, OpCodes.Ldc_I4, thisCase.val2 - offset);
-                        ilGen.Emit (switchStmt, OpCodes.Ble_Un, thisCase.label);
-                    }
-                    thisCase = thisCase.nextSortedCase;
-                }
-            }
-            ilGen.Emit (switchStmt, OpCodes.Br, defaultLabel);
-
-            /*
-             * Output code for the cases themselves, in the order given by the programmer, 
-             * so they fall through as programmer wants.  This includes the default case, if any.
-             *
-             * Each label is jumped to with the index still on the stack.  So pop it off in case
-             * the case body does a goto outside the switch or a return.  If the case body might
-             * fall through to the next case or the bottom of the switch, push a zero so the stack
-             * matches in all cases.
-             */
-            for (TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase) {
-                ilGen.MarkLabel (thisCase.label);   // the branch comes here
-                ilGen.Emit (thisCase, OpCodes.Pop); // pop the integer index off stack
-                mightGetHere = true;            // it's possible to get here
-                for (TokenStmt stmt = thisCase.stmts; stmt != null; stmt = (TokenStmt)(stmt.nextToken)) {
-                    GenerateStmt (stmt);        // output the case/explicit default body
-                }
-                if (mightGetHere) {
-                    ilGen.Emit (thisCase, OpCodes.Ldc_I4_0);
-                                    // in case we fall through, push a dummy integer index
-                }
-            }
-
-            /*
-             * If no explicit default case, output the default label here.
-             */
-            if (defaultCase == null) {
-                ilGen.MarkLabel (defaultLabel);
-                mightGetHere = true;
-            }
-
-            /*
-             * If the last case of the switch falls through out the bottom,
-             * we have to pop the index still on the stack.
-             */
-            if (mightGetHere) {
-                ilGen.Emit (switchStmt, OpCodes.Pop);
-            }
-
-            /*
-             * Output the 'break' statement target label.
-             * Note that the integer index is not on the stack at this point.
-             */
-            if (curBreakTarg.used) {
-                ilGen.MarkLabel (curBreakTarg.label);
-                mightGetHere = true;
-            }
-
-            curBreakTarg = oldBreakTarg;
-        }
-
-        private void GenerateStmtSwitchStr (CompValu testRVal, TokenStmtSwitch switchStmt)
-        {
-            BreakContTarg   oldBreakTarg = curBreakTarg;
-            ScriptMyLabel   defaultLabel = null;
-            TokenSwitchCase caseTreeTop  = null;
-            TokenSwitchCase defaultCase  = null;
-
-            curBreakTarg = new BreakContTarg (this, "switchbreak_" + switchStmt.Unique);
-
-            /*
-             * Make sure value is in a temp so we don't compute it more than once.
-             */
-            if (!(testRVal is CompValuTemp)) {
-                CompValuTemp temp = new CompValuTemp (testRVal.type, this);
-                testRVal.PushVal (this, switchStmt);
-                temp.Pop (this, switchStmt);
-                testRVal = temp;
-            }
-
-            /*
-             * Build tree of cases.
-             * There should not be any overlapping of values.
-             */
-            for (TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase) {
-                thisCase.label = ilGen.DefineLabel ("case");
-
-                /*
-                 * The default case if any, goes in its own separate slot.
-                 */
-                if (thisCase.rVal1 == null) {
-                    if (defaultCase != null) {
-                        ErrorMsg (thisCase, "only one default case allowed");
-                        ErrorMsg (defaultCase, "...prior default case");
-                        return;
-                    }
-                    defaultCase  = thisCase;
-                    defaultLabel = thisCase.label;
-                    continue;
-                }
-
-                /*
-                 * Evaluate case operands, they must be compile-time string constants.
-                 */
-                CompValu rVal = GenerateFromRVal (thisCase.rVal1);
-                if (!IsConstStrExpr (rVal, out thisCase.str1)) {
-                    ErrorMsg (thisCase.rVal1, "must be compile-time string constant");
-                    continue;
-                }
-                thisCase.str2 = thisCase.str1;
-                if (thisCase.rVal2 != null) {
-                    rVal = GenerateFromRVal (thisCase.rVal2);
-                    if (!IsConstStrExpr (rVal, out thisCase.str2)) {
-                        ErrorMsg (thisCase.rVal2, "must be compile-time string constant");
-                        continue;
-                    }
-                }
-                if (String.Compare (thisCase.str2, thisCase.str1, StringComparison.Ordinal) < 0) {
-                    ErrorMsg (thisCase.rVal2, "must be .ge. first value for the case");
-                    continue;
-                }
-
-                /*
-                 * Insert into list, sorted by value.
-                 * Note that both limits are inclusive.
-                 */
-                caseTreeTop = InsertCaseInTree (caseTreeTop, thisCase);
-            }
-
-            /*
-             * Balance tree so we end up generating code that does O(log2 n) comparisons.
-             */
-            caseTreeTop = BalanceTree (caseTreeTop);
-
-            /*
-             * Output compare and branch instructions in a tree-like fashion so we do O(log2 n) comparisons.
-             */
-            if (defaultLabel == null) {
-                defaultLabel = ilGen.DefineLabel ("default");
-            }
-            OutputStrCase (testRVal, caseTreeTop, defaultLabel);
-
-            /*
-             * Output code for the cases themselves, in the order given by the programmer, 
-             * so they fall through as programmer wants.  This includes the default case, if any.
-             */
-            for (TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase) {
-                ilGen.MarkLabel (thisCase.label);   // the branch comes here
-                mightGetHere = true;            // it's possible to get here
-                for (TokenStmt stmt = thisCase.stmts; stmt != null; stmt = (TokenStmt)(stmt.nextToken)) {
-                    GenerateStmt (stmt);        // output the case/explicit default body
-                }
-            }
-
-            /*
-             * If no explicit default case, output the default label here.
-             */
-            if (defaultCase == null) {
-                ilGen.MarkLabel (defaultLabel);
-                mightGetHere = true;
-            }
-
-            /*
-             * Output the 'break' statement target label.
-             */
-            if (curBreakTarg.used) {
-                ilGen.MarkLabel (curBreakTarg.label);
-                mightGetHere = true;
-            }
-
-            curBreakTarg = oldBreakTarg;
-        }
-
-        /**
-         * @brief Insert a case in a tree of cases
-         * @param r = root of existing cases to insert into
-         * @param n = new case being inserted
-         * @returns new root with new case inserted
-         */
-        private TokenSwitchCase InsertCaseInTree (TokenSwitchCase r, TokenSwitchCase n)
-        {
-            if (r == null) return n;
-
-            TokenSwitchCase t = r;
-            while (true) {
-                if (String.Compare (n.str2, t.str1, StringComparison.Ordinal) < 0) {
-                    if (t.lowerCase == null) {
-                        t.lowerCase = n;
-                        break;
-                    }
-                    t = t.lowerCase;
-                    continue;
-                }
-                if (String.Compare (n.str1, t.str2, StringComparison.Ordinal) > 0) {
-                    if (t.higherCase == null) {
-                        t.higherCase = n;
-                        break;
-                    }
-                    t = t.higherCase;
-                    continue;
-                }
-                ErrorMsg (n, "duplicate case");
-                ErrorMsg (r, "...duplicate of");
-                break;
-            }
-            return r;
-        }
-
-        /**
-         * @brief Balance a tree so left & right halves contain same number within +-1
-         * @param r = root of tree to balance
-         * @returns new root
-         */
-        private static TokenSwitchCase BalanceTree (TokenSwitchCase r)
-        {
-            if (r == null) return r;
-
-            int lc = CountTree (r.lowerCase);
-            int hc = CountTree (r.higherCase);
-            TokenSwitchCase n, x;
-
-            /*
-             * If lower side is heavy, move highest nodes from lower side to 
-             * higher side until balanced.
-             */
-            while (lc > hc + 1) {
-                x = ExtractHighest (r.lowerCase, out n);
-                n.lowerCase  = x;
-                n.higherCase = r;
-                r.lowerCase  = null;
-                r = n;
-                lc --;
-                hc ++;
-            }
-
-            /*
-             * If higher side is heavy, move lowest nodes from higher side to 
-             * lower side until balanced.
-             */
-            while (hc > lc + 1) {
-                x = ExtractLowest (r.higherCase, out n);
-                n.higherCase = x;
-                n.lowerCase  = r;
-                r.higherCase = null;
-                r = n;
-                lc ++;
-                hc --;
-            }
-
-            /*
-             * Now balance each side because they can be lopsided individually.
-             */
-            r.lowerCase  = BalanceTree (r.lowerCase);
-            r.higherCase = BalanceTree (r.higherCase);
-            return r;
-        }
-
-        /**
-         * @brief Get number of nodes in a tree
-         * @param n = root of tree to count
-         * @returns number of nodes including root
-         */
-        private static int CountTree (TokenSwitchCase n)
-        {
-            if (n == null) return 0;
-            return 1 + CountTree (n.lowerCase) + CountTree (n.higherCase);
-        }
-
-        // Extract highest node from a tree
-        // @param r = root of tree to extract highest from
-        // @returns new root after node has been extracted
-        //          n = node that was extracted from tree
-        private static TokenSwitchCase ExtractHighest (TokenSwitchCase r, out TokenSwitchCase n)
-        {
-            if (r.higherCase == null) {
-                n = r;
-                return r.lowerCase;
-            }
-            r.higherCase = ExtractHighest (r.higherCase, out n);
-            return r;
-        }
-
-        // Extract lowest node from a tree
-        // @param r = root of tree to extract lowest from
-        // @returns new root after node has been extracted
-        //          n = node that was extracted from tree
-        private static TokenSwitchCase ExtractLowest (TokenSwitchCase r, out TokenSwitchCase n)
-        {
-            if (r.lowerCase == null) {
-                n = r;
-                return r.higherCase;
-            }
-            r.lowerCase = ExtractLowest (r.lowerCase, out n);
-            return r;
-        }
-
-        /**
-         * Output code for string-style case of a switch/case to jump to the script code associated with the case.
-         * @param testRVal = value being switched on
-         * @param thisCase = case that the code is being output for
-         * @param defaultLabel = where the default clause is (or past all cases if none)
-         * Note:
-         *   Outputs code for this case and the lowerCase and higherCases if any.
-         *   If no lowerCase or higherCase, outputs a br to defaultLabel so this code never falls through.
-         */
-        private void OutputStrCase (CompValu testRVal, TokenSwitchCase thisCase, ScriptMyLabel defaultLabel)
-        {
-            /*
-             * If nothing lower on tree and there is a single case value, 
-             * just do one compare for equality.
-             */
-            if ((thisCase.lowerCase == null) && (thisCase.higherCase == null) && (thisCase.str1 == thisCase.str2)) {
-                testRVal.PushVal (this, thisCase, tokenTypeStr);
-                ilGen.Emit (thisCase, OpCodes.Ldstr,   thisCase.str1);
-                ilGen.Emit (thisCase, OpCodes.Ldc_I4,  (int)StringComparison.Ordinal);
-                ilGen.Emit (thisCase, OpCodes.Call,    stringCompareMethodInfo);
-                ilGen.Emit (thisCase, OpCodes.Brfalse, thisCase.label);
-                ilGen.Emit (thisCase, OpCodes.Br,      defaultLabel);
-                return;
-            }
-
-            /*
-             * Determine where to jump if switch value is lower than lower case value.
-             */
-            ScriptMyLabel lowerLabel = defaultLabel;
-            if (thisCase.lowerCase != null) {
-                lowerLabel = ilGen.DefineLabel ("lower");
-            }
-
-            /*
-             * If single case value, put comparison result in this temp.
-             */
-            CompValuTemp cmpv1 = null;
-            if (thisCase.str1 == thisCase.str2) {
-                cmpv1 = new CompValuTemp (tokenTypeInt, this);
-            }
-
-            /*
-             * If switch value .lt. lower case value, jump to lower label.
-             * Maybe save comparison result in a temp.
-             */
-            testRVal.PushVal (this, thisCase, tokenTypeStr);
-            ilGen.Emit (thisCase, OpCodes.Ldstr,  thisCase.str1);
-            ilGen.Emit (thisCase, OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
-            ilGen.Emit (thisCase, OpCodes.Call,   stringCompareMethodInfo);
-            if (cmpv1 != null) {
-                ilGen.Emit (thisCase, OpCodes.Dup);
-                cmpv1.Pop (this, thisCase);
-            }
-            ilGen.Emit (thisCase, OpCodes.Ldc_I4_0);
-            ilGen.Emit (thisCase, OpCodes.Blt,    lowerLabel);
-
-            /*
-             * If switch value .le. higher case value, jump to case code.
-             * Maybe get comparison from the temp.
-             */
-            if (cmpv1 == null) {
-                testRVal.PushVal (this, thisCase, tokenTypeStr);
-                ilGen.Emit (thisCase, OpCodes.Ldstr,  thisCase.str2);
-                ilGen.Emit (thisCase, OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
-                ilGen.Emit (thisCase, OpCodes.Call,   stringCompareMethodInfo);
-            } else {
-                cmpv1.PushVal (this, thisCase);
-            }
-            ilGen.Emit (thisCase, OpCodes.Ldc_I4_0);
-            ilGen.Emit (thisCase, OpCodes.Ble,    thisCase.label);
-
-            /*
-             * Output code for higher comparison if any.
-             */
-            if (thisCase.higherCase == null) {
-                ilGen.Emit (thisCase, OpCodes.Br, defaultLabel);
-            } else {
-                OutputStrCase (testRVal, thisCase.higherCase, defaultLabel);
-            }
-
-            /*
-             * Output code for lower comparison if any.
-             */
-            if (thisCase.lowerCase != null) {
-                ilGen.MarkLabel (lowerLabel);
-                OutputStrCase (testRVal, thisCase.lowerCase, defaultLabel);
-            }
-        }
-
-        /**
-         * @brief output code for a throw statement.
-         * @param throwStmt = throw statement token, including value to be thrown
-         */
-        private void GenerateStmtThrow (TokenStmtThrow throwStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * 'throw' statements never fall through.
-             */
-            mightGetHere = false;
-
-            /*
-             * Output code for either a throw or a rethrow.
-             */
-            if (throwStmt.rVal == null) {
-                for (TokenStmtBlock blk = curStmtBlock; blk != null; blk = blk.outerStmtBlock) {
-                    if (curStmtBlock.isCatch) {
-                        ilGen.Emit (throwStmt, OpCodes.Rethrow);
-                        return;
-                    }
-                }
-                ErrorMsg (throwStmt, "rethrow allowed only in catch clause");
-            } else {
-                CompValu rVal = GenerateFromRVal (throwStmt.rVal);
-                rVal.PushVal (this, throwStmt.rVal, tokenTypeObj);
-                ilGen.Emit (throwStmt, OpCodes.Call, thrownExceptionWrapMethodInfo);
-                ilGen.Emit (throwStmt, OpCodes.Throw);
-            }
-        }
-
-        /**
-         * @brief output code for a try/catch/finally block
-         */
-        private void GenerateStmtTry (TokenStmtTry tryStmt)
-        {
-            if (!mightGetHere) return;
-
-            /*
-             * Reducer should make sure we have exactly one of catch or finally.
-             */
-            if ((tryStmt.catchStmt == null) && (tryStmt.finallyStmt == null)) {
-                throw new Exception ("must have a catch or a finally on try");
-            }
-            if ((tryStmt.catchStmt != null) && (tryStmt.finallyStmt != null)) {
-                throw new Exception ("can't have both catch and finally on same try");
-            }
-
-            /*
-             * Stack the call labels.
-             * Try blocks have their own series of call labels.
-             */
-            ScriptMyLocal saveCallNo = actCallNo;
-            LinkedList<CallLabel> saveCallLabels = actCallLabels;
-
-            /*
-             * Generate code for either try { } catch { } or try { } finally { }.
-             */
-            if (tryStmt.catchStmt   != null) GenerateStmtTryCatch   (tryStmt);
-            if (tryStmt.finallyStmt != null) GenerateStmtTryFinally (tryStmt);
-
-            /*
-             * Restore call labels.
-             */
-            actCallNo     = saveCallNo;
-            actCallLabels = saveCallLabels;
-        }
-
-
-        /**
-         * @brief output code for a try/catch block
-         *
-         *      int    __tryCallNo = -1;                                   // call number within try { } subblock
-         *      int    __catCallNo = -1;                                   // call number within catch { } subblock
-         *      Exception __catThrown = null;                              // caught exception
-         *    <oldCallLabel>:                                              // the outside world jumps here to restore us no matter ...
-         *      try {                                                      // ... where we actually were inside of try/catch
-         *          if (__tryCallNo >= 0) goto tryCallSw;                  // maybe go do restore
-         *          <try body using __tryCallNo>                           // execute script-defined code
-         *                                                                 // ...stack capture WILL run catch { } subblock
-         *          leave tryEnd;                                          // exits
-         *        tryThrow:<tryCallLabel>:
-         *          throw new ScriptRestoreCatchException(__catThrown);    // catch { } was running, jump to its beginning
-         *        tryCallSw:                                               // restoring...
-         *          switch (__tryCallNo) back up into <try body>           // not catching, jump back inside try
-         *      } catch (Exception exc) {
-         *          exc = ScriptRestoreCatchException.Unwrap(exc);         // unwrap possible ScriptRestoreCatchException
-         *          if (exc == null) goto catchRetro;                      // rethrow if IXMRUncatchable (eg, StackCaptureException)
-         *          __catThrown = exc;                                     // save what was thrown so restoring try { } will throw it again
-         *          catchVar = exc;                                        // set up script-visible variable
-         *          __tryCallNo = tryThrow:<tryCallLabel>
-         *          if (__catCallNo >= 0) goto catchCallSw;                // if restoring, go check below
-         *          <catch body using __catCallNo>                         // normal, execute script-defined code
-         *          leave tryEnd;                                          // all done, exit catch { }
-         *        catchRetro:
-         *          rethrow;
-         *        catchCallSw:
-         *          switch (__catCallNo) back up into <catch body>         // restart catch { } code wherever it was
-         *      }
-         *    tryEnd:
-         */
-        private void GenerateStmtTryCatch (TokenStmtTry tryStmt)
-        {
-            CompValuTemp tryCallNo = new CompValuTemp (tokenTypeInt, this);
-            CompValuTemp catCallNo = new CompValuTemp (tokenTypeInt, this);
-            CompValuTemp catThrown = new CompValuTemp (tokenTypeExc, this);
-
-            ScriptMyLabel tryCallSw   = ilGen.DefineLabel ("__tryCallSw_"   + tryStmt.Unique);
-            ScriptMyLabel catchRetro  = ilGen.DefineLabel ("__catchRetro_"  + tryStmt.Unique);
-            ScriptMyLabel catchCallSw = ilGen.DefineLabel ("__catchCallSw_" + tryStmt.Unique);
-            ScriptMyLabel tryEnd      = ilGen.DefineLabel ("__tryEnd_"      + tryStmt.Unique);
-
-            SetCallNo (tryStmt, tryCallNo, -1);
-            SetCallNo (tryStmt, catCallNo, -1);
-            ilGen.Emit (tryStmt, OpCodes.Ldnull);
-            catThrown.Pop (this, tryStmt);
-
-            new CallLabel (this, tryStmt);              //   <oldcalllabel>:
-            ilGen.BeginExceptionBlock ();               //     try {
-            openCallLabel = null;
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "enter try*: " + tryStmt.line + " callMode=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                PushXMRInst ();
-                ilGen.Emit (tryStmt, OpCodes.Ldfld, callModeFieldInfo);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " tryCallNo=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                tryCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " catThrown.IsNull=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catThrown.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Ldnull);
-                ilGen.Emit (tryStmt, OpCodes.Ceq);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " catCallNo=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            GetCallNo (tryStmt, tryCallNo);             //         if (__tryCallNo >= 0) goto tryCallSw;
-            ilGen.Emit (tryStmt, OpCodes.Ldc_I4_0);
-            ilGen.Emit (tryStmt, OpCodes.Bge, tryCallSw);
-
-            actCallNo = tryCallNo.localBuilder;                     // set up __tryCallNo for call labels
-            actCallLabels = new LinkedList<CallLabel> ();
-
-            GenerateStmtBlock (tryStmt.tryStmt);            // output the try block statement subblock
-
-            bool tryBlockFallsOutBottom = mightGetHere;
-            if (tryBlockFallsOutBottom) {
-                new CallLabel (this, tryStmt);          //       <tryCallLabel>:
-                ilGen.Emit (tryStmt, OpCodes.Leave, tryEnd);    //         leave tryEnd;
-                openCallLabel = null;
-            }
-
-            CallLabel tryThrow = new CallLabel (this, tryStmt); //       tryThrow:<tryCallLabel>:
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "tryThrow*: " + tryStmt.line + " catThrown=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catThrown.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-            catThrown.PushVal (this, tryStmt);          //         throw new ScriptRestoreCatchException (__catThrown);
-            ilGen.Emit (tryStmt, OpCodes.Newobj, scriptRestoreCatchExceptionConstructorInfo);
-            ilGen.Emit (tryStmt, OpCodes.Throw);
-            openCallLabel = null;
-
-            ilGen.MarkLabel (tryCallSw);                //       tryCallSw:
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "tryCallSw*: " + tryStmt.line + " tryCallNo=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                tryCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-            OutputCallNoSwitchStmt ();              //         switch (tryCallNo) ...
-
-            CompValuLocalVar catchVarLocExc = null;
-            CompValuTemp catchVarLocStr = null;
-
-            if (tryStmt.catchVar.type.ToSysType () == typeof (Exception)) {
-                catchVarLocExc = new CompValuLocalVar (tryStmt.catchVar.type, tryStmt.catchVar.name.val, this);
-            } else if (tryStmt.catchVar.type.ToSysType () == typeof (String)) {
-                catchVarLocStr = new CompValuTemp (tryStmt.catchVar.type, this);
-            }
-
-            ScriptMyLocal excLocal = ilGen.DeclareLocal (typeof (String), "catchstr_" + tryStmt.Unique);
-
-            ilGen.BeginCatchBlock (typeof (Exception));     // start of the catch block that can catch any exception
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldstr, "enter catch*: " + tryStmt.line + " callMode=");
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                PushXMRInst ();
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldfld, callModeFieldInfo);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldstr, " catCallNo=");
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldstr, " exc=");
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Dup);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, scriptRestoreCatchExceptionUnwrap);
-                                        // exc = ScriptRestoreCatchException.Unwrap (exc);
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Dup);        // rethrow if IXMRUncatchable (eg, StackCaptureException)
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Brfalse, catchRetro);
-            if (tryStmt.catchVar.type.ToSysType () == typeof (Exception)) {
-                tryStmt.catchVar.location = catchVarLocExc;
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Dup);
-                catThrown.Pop (this, tryStmt);              // store exception object in catThrown
-                catchVarLocExc.Pop (this, tryStmt.catchVar.name);      // also store in script-visible variable
-            } else if (tryStmt.catchVar.type.ToSysType () == typeof (String)) {
-                tryStmt.catchVar.location = catchVarLocStr;
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Dup);
-                catThrown.Pop (this, tryStmt);              // store exception object in catThrown
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Call, catchExcToStrMethodInfo);
-
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Stloc, excLocal);
-                catchVarLocStr.PopPre (this, tryStmt.catchVar.name);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldloc, excLocal);
-                catchVarLocStr.PopPost (this, tryStmt.catchVar.name, tokenTypeStr);
-            } else {
-                throw new Exception ("bad catch var type " + tryStmt.catchVar.type.ToString ());
-            }
-
-            SetCallNo (tryStmt, tryCallNo, tryThrow.index);     // __tryCallNo = tryThrow so it knows to do 'throw catThrown' on restore
-
-            GetCallNo (tryStmt, catCallNo);             // if (__catCallNo >= 0) goto catchCallSw;
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Ldc_I4_0);
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Bge, catchCallSw);
-
-            actCallNo = catCallNo.localBuilder;                 // set up __catCallNo for call labels
-            actCallLabels.Clear ();
-            mightGetHere = true;                    // if we can get to the 'try' assume we can get to the 'catch'
-            GenerateStmtBlock (tryStmt.catchStmt);          // output catch clause statement subblock
-
-            if (mightGetHere) {
-                new CallLabel (this, tryStmt.catchStmt);
-                ilGen.Emit (tryStmt.catchStmt, OpCodes.Leave, tryEnd);
-                openCallLabel = null;
-            }
-
-            ilGen.MarkLabel (catchRetro);               // not a script-visible exception, rethrow it
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Pop);
-            ilGen.Emit (tryStmt.catchStmt, OpCodes.Rethrow);
-
-            ilGen.MarkLabel (catchCallSw);
-            OutputCallNoSwitchStmt ();              // restoring, jump back inside script-defined body
-
-            ilGen.EndExceptionBlock ();
-            ilGen.MarkLabel (tryEnd);
-
-            mightGetHere |= tryBlockFallsOutBottom;         // also get here if try body falls out bottom
-        }
-
-        /**
-         * @brief output code for a try/finally block
-         *
-         * This is such a mess because there is hidden state for the finally { } that we have to recreate.
-         * The finally { } can be entered either via an exception being thrown in the try { } or a leave 
-         * being executed in the try { } whose target is outside the try { } finally { }.
-         *
-         * For the thrown exception case, we slip in a try { } catch { } wrapper around the original try { }
-         * body.  This will sense any thrown exception that would execute the finally { }.  Then we have our
-         * try { } throw the exception on restore which gets the finally { } called and on its way again.
-         *
-         * For the leave case, we prefix all leave instructions with a call label and we explicitly chain
-         * all leaves through each try { } that has an associated finally { } that the leave would unwind 
-         * through.  This gets each try { } to simply jump to the correct leave instruction which immediately 
-         * invokes the corresponding finally { } and then chains to the next leave instruction on out until 
-         * it gets to its target.
-         *
-         *      int    __finCallNo = -1;                                     // call number within finally { } subblock
-         *      int    __tryCallNo = -1;                                     // call number within try { } subblock
-         *      Exception __catThrown = null;                                // caught exception
-         *    <oldCallLabel>:                                                // the outside world jumps here to restore us no matter ...
-         *      try {                                                        // ... where we actually were inside of try/finally
-         *          try {
-         *              if (__tryCallNo >= 0) goto tryCallSw;                // maybe go do restore
-         *              <try body using __tryCallNo>                         // execute script-defined code
-         *                                                                   // ...stack capture WILL run catch/finally { } subblock
-         *              leave tryEnd;                                        // executes finally { } subblock and exits
-         *            tryThrow:<tryCallLabel>:
-         *              throw new ScriptRestoreCatchException(__catThrown);  // catch { } was running, jump to its beginning
-         *            tryCallSw:                                             // restoring...
-         *              switch (__tryCallNo) back up into <try body>         // jump back inside try, ...
-         *                                                                   // ... maybe to a leave if we were doing finally { } subblock
-         *          } catch (Exception exc) {                                // in case we're getting to finally { } via a thrown exception:
-         *              exc = ScriptRestoreCatchException.Unwrap(exc);       // unwrap possible ScriptRestoreCatchException
-         *              if (callMode == CallMode_SAVE) goto catchRetro;      // don't touch anything if capturing stack
-         *              __catThrown = exc;                                   // save exception so try { } can throw it on restore
-         *              __tryCallNo = tryThrow:<tryCallLabel>;               // tell try { } to throw it on restore
-         *            catchRetro:
-         *              rethrow;                                             // in any case, go on to finally { } subblock now
-         *          }
-         *      } finally {
-         *          if (callMode == CallMode_SAVE) goto finEnd;              // don't touch anything if capturing stack
-         *          if (__finCallNo >= 0) goto finCallSw;                    // maybe go do restore
-         *          <finally body using __finCallNo>                         // normal, execute script-defined code
-         *        finEnd:
-         *          endfinally                                               // jump to leave/throw target or next outer finally { }
-         *        finCallSw:
-         *          switch (__finCallNo) back up into <finally body>         // restoring, restart finally { } code wherever it was
-         *      }
-         *    tryEnd:
-         */
-        private void GenerateStmtTryFinally (TokenStmtTry tryStmt)
-        {
-            CompValuTemp finCallNo = new CompValuTemp (tokenTypeInt, this);
-            CompValuTemp tryCallNo = new CompValuTemp (tokenTypeInt, this);
-            CompValuTemp catThrown = new CompValuTemp (tokenTypeExc, this);
-
-            ScriptMyLabel tryCallSw   = ilGen.DefineLabel (       "__tryCallSw_"   + tryStmt.Unique);
-            ScriptMyLabel catchRetro  = ilGen.DefineLabel (       "__catchRetro_"  + tryStmt.Unique);
-            ScriptMyLabel finCallSw   = ilGen.DefineLabel (       "__finCallSw_"   + tryStmt.Unique);
-            BreakContTarg finEnd      = new BreakContTarg (this, "__finEnd_"      + tryStmt.Unique);
-            ScriptMyLabel tryEnd      = ilGen.DefineLabel (       "__tryEnd_"      + tryStmt.Unique);
-
-            SetCallNo (tryStmt, finCallNo, -1);
-            SetCallNo (tryStmt, tryCallNo, -1);
-            ilGen.Emit (tryStmt, OpCodes.Ldnull);
-            catThrown.Pop (this, tryStmt);
-
-            new CallLabel (this, tryStmt);              //   <oldcalllabel>:
-            ilGen.BeginExceptionBlock ();               //     try {
-            ilGen.BeginExceptionBlock ();               //     try {
-            openCallLabel = null;
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "enter try*: " + tryStmt.line + " callMode=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                PushXMRInst ();
-                ilGen.Emit (tryStmt, OpCodes.Ldfld, callModeFieldInfo);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " tryCallNo=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                tryCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " finCallNo=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                finCallNo.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " catThrown.IsNull=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catThrown.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Ldnull);
-                ilGen.Emit (tryStmt, OpCodes.Ceq);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-
-            GetCallNo (tryStmt, tryCallNo);             //         if (__tryCallNo >= 0) goto tryCallSw;
-            ilGen.Emit (tryStmt, OpCodes.Ldc_I4_0);
-            ilGen.Emit (tryStmt, OpCodes.Bge, tryCallSw);
-
-            actCallNo = tryCallNo.localBuilder;                     // set up __tryCallNo for call labels
-            actCallLabels = new LinkedList<CallLabel> ();
-
-            GenerateStmtBlock (tryStmt.tryStmt);            // output the try block statement subblock
-
-            if (mightGetHere) {
-                new CallLabel (this, tryStmt);          //       <newCallLabel>:
-                ilGen.Emit (tryStmt, OpCodes.Leave, tryEnd);    //         leave tryEnd;
-                openCallLabel = null;
-            }
-
-            foreach (IntermediateLeave iLeave in tryStmt.iLeaves.Values) {
-                ilGen.MarkLabel (iLeave.jumpIntoLabel);     //       intr2_exit:
-                new CallLabel (this, tryStmt);          //         tryCallNo = n;
-                ilGen.Emit (tryStmt, OpCodes.Leave, iLeave.jumpAwayLabel);  //    __callNo_n_: leave int1_exit;
-                openCallLabel = null;
-            }
-
-            CallLabel tryThrow = new CallLabel (this, tryStmt); //       tryThrow:<tryCallLabel>:
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "tryThrow*: " + tryStmt.line + " catThrown=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                catThrown.PushVal (this, tryStmt);
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-            catThrown.PushVal (this, tryStmt);          //         throw new ScriptRestoreCatchException (__catThrown);
-            ilGen.Emit (tryStmt, OpCodes.Newobj, scriptRestoreCatchExceptionConstructorInfo);
-            ilGen.Emit (tryStmt, OpCodes.Throw);
-            openCallLabel = null;
-
-            ilGen.MarkLabel (tryCallSw);                //       tryCallSw:
-            OutputCallNoSwitchStmt ();              //         switch (tryCallNo) ...
-                                        //     }
-
-            ilGen.BeginCatchBlock (typeof (Exception));     // start of the catch block that can catch any exception
-            if (DEBUG_TRYSTMT) {
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "enter catch*: " + tryStmt.line + " callMode=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                PushXMRInst ();
-                ilGen.Emit (tryStmt, OpCodes.Ldfld, callModeFieldInfo);
-                ilGen.Emit (tryStmt, OpCodes.Box, typeof (int));
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, " exc=");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Dup);
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-                ilGen.Emit (tryStmt, OpCodes.Ldstr, "\n");
-                ilGen.Emit (tryStmt, OpCodes.Call, consoleWriteMethodInfo);
-            }
-            ilGen.Emit (tryStmt, OpCodes.Call, scriptRestoreCatchExceptionUnwrap);  // exc = ScriptRestoreCatchException.Unwrap (exc);
-            PushXMRInst ();                     // if (callMode == CallMode_SAVE) goto catchRetro;
-            ilGen.Emit (tryStmt, OpCodes.Ldfld, callModeFieldInfo);
-            ilGen.Emit (tryStmt, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
-            ilGen.Emit (tryStmt, OpCodes.Beq, catchRetro);
-
-            catThrown.Pop (this, tryStmt);              // __catThrown = exc;
-            SetCallNo (tryStmt, tryCallNo, tryThrow.index);     // __tryCallNo = tryThrow:<tryCallLabel>;
-            ilGen.Emit (tryStmt, OpCodes.Rethrow);
-
-            ilGen.MarkLabel (catchRetro);               // catchRetro:
-            ilGen.Emit (tryStmt, OpCodes.Pop);
-            ilGen.Emit (tryStmt, OpCodes.Rethrow);          //    rethrow;
-
-            ilGen.EndExceptionBlock ();             // }
-
-            ilGen.BeginFinallyBlock ();             // start of the finally block
-
-            PushXMRInst ();                     // if (callMode == CallMode_SAVE) goto finEnd;
-            ilGen.Emit (tryStmt, OpCodes.Ldfld, callModeFieldInfo);
-            ilGen.Emit (tryStmt, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
-            ilGen.Emit (tryStmt, OpCodes.Beq, finEnd.label);
-
-            GetCallNo (tryStmt, finCallNo);             // if (__finCallNo >= 0) goto finCallSw;
-            ilGen.Emit (tryStmt, OpCodes.Ldc_I4_0);
-            ilGen.Emit (tryStmt, OpCodes.Bge, finCallSw);
-
-            actCallNo = finCallNo.localBuilder;                 // set up __finCallNo for call labels
-            actCallLabels.Clear ();
-            mightGetHere = true;                    // if we can get to the 'try' assume we can get to the 'finally'
-            GenerateStmtBlock (tryStmt.finallyStmt);        // output finally clause statement subblock
-
-            ilGen.MarkLabel (finEnd.label);             // finEnd:
-            ilGen.Emit (tryStmt, OpCodes.Endfinally);       //    return out to next finally { } or catch { } or leave target
-
-            ilGen.MarkLabel (finCallSw);                // restore mode, switch (finCallNo) ...
-            OutputCallNoSwitchStmt ();
-
-            ilGen.EndExceptionBlock ();
-            ilGen.MarkLabel (tryEnd);
-
-            mightGetHere |= finEnd.used;                // get here if finally body falls through or has a break statement
-        }
-
-        /**
-         * @brief Generate code to initialize a variable to its default value.
-         */
-        private void GenerateStmtVarIniDef (TokenStmtVarIniDef varIniDefStmt)
-        {
-            if (!mightGetHere) return;
-
-            CompValu left = GenerateFromLVal (varIniDefStmt.var);
-            left.PopPre (this, varIniDefStmt);
-            PushDefaultValue (left.type);
-            left.PopPost (this, varIniDefStmt);
-        }
-
-        /**
-         * @brief generate code for a 'while' statement including the loop body.
-         */
-        private void GenerateStmtWhile (TokenStmtWhile whileStmt)
-        {
-            if (!mightGetHere) return;
-
-            BreakContTarg oldBreakTarg = curBreakTarg;
-            BreakContTarg oldContTarg  = curContTarg;
-            ScriptMyLabel loopLabel    = ilGen.DefineLabel ("whileloop_" + whileStmt.Unique);
-
-            curBreakTarg = new BreakContTarg (this, "whilebreak_" + whileStmt.Unique);
-            curContTarg  = new BreakContTarg (this, "whilecont_"  + whileStmt.Unique);
-
-            ilGen.MarkLabel (loopLabel);                                          // loop:
-            CompValu testRVal = GenerateFromRVal (whileStmt.testRVal);            //   testRVal = while test expression
-            if (!IsConstBoolExprTrue (testRVal)) {
-                testRVal.PushVal (this, whileStmt.testRVal, tokenTypeBool);   //   if (!testRVal)
-                ilGen.Emit (whileStmt, OpCodes.Brfalse, curBreakTarg.label);  //      goto break
-                curBreakTarg.used = true;
-            }
-            GenerateStmt (whileStmt.bodyStmt);                                    //   while body statement
-            if (curContTarg.used) {
-                ilGen.MarkLabel (curContTarg.label);                          // cont:
-                mightGetHere = true;
-            }
-            if (mightGetHere) {
-                EmitCallCheckRun (whileStmt, false);                          //   __sw.CheckRun()
-                ilGen.Emit (whileStmt, OpCodes.Br, loopLabel);                //   goto loop
-            }
-            mightGetHere = curBreakTarg.used;
-            if (mightGetHere) {
-                ilGen.MarkLabel (curBreakTarg.label);                         // done:
-            }
-
-            curBreakTarg = oldBreakTarg;
-            curContTarg  = oldContTarg;
-        }
-
-        /**
-         * @brief process a local variable declaration statement, possibly with initialization expression.
-         *        Note that the function header processing allocated stack space (CompValuTemp) for the
-         *        variable and now all we do is write its initialization value.
-         */
-        private void GenerateDeclVar (TokenDeclVar declVar)
-        {
-            /*
-             * Script gave us an initialization value, so just store init value in var like an assignment statement.
-             * If no init given, set it to its default value.
-             */
-            CompValu local = declVar.location;
-            if (declVar.init != null) {
-                CompValu rVal = GenerateFromRVal (declVar.init, local.GetArgTypes ());
-                local.PopPre  (this, declVar);
-                rVal.PushVal  (this, declVar.init, declVar.type);
-                local.PopPost (this, declVar);
-            } else {
-                local.PopPre  (this, declVar);
-                PushDefaultValue (declVar.type);
-                local.PopPost (this, declVar);
-            }
-        }
-
-        /**
-         * @brief Get the type and location of an L-value (eg, variable)
-         * @param lVal    = L-value expression to evaluate
-         * @param argsig  = null: it's a field/property
-         *                  else: select overload method that fits these arg types
-         */
-        private CompValu GenerateFromLVal (TokenLVal lVal)
-        {
-            return GenerateFromLVal (lVal, null);
-        }
-        private CompValu GenerateFromLVal (TokenLVal lVal, TokenType[] argsig)
-        {
-            if (lVal is TokenLValArEle)     return GenerateFromLValArEle     ((TokenLValArEle)lVal);
-            if (lVal is TokenLValBaseField) return GenerateFromLValBaseField ((TokenLValBaseField)lVal, argsig);
-            if (lVal is TokenLValIField)    return GenerateFromLValIField    ((TokenLValIField)lVal,    argsig);
-            if (lVal is TokenLValName)      return GenerateFromLValName      ((TokenLValName)lVal,      argsig);
-            if (lVal is TokenLValSField)    return GenerateFromLValSField    ((TokenLValSField)lVal,    argsig);
-            throw new Exception ("bad lval class");
-        }
-
-        /**
-         * @brief we have an L-value token that is an element within an array.
-         * @returns a CompValu giving the type and location of the element of the array.
-         */
-        private CompValu GenerateFromLValArEle (TokenLValArEle lVal)
-        {
-            CompValu subCompValu;
-
-            /*
-             * Compute location of array itself.
-             */
-            CompValu baseCompValu = GenerateFromRVal (lVal.baseRVal);
-
-            /*
-             * Maybe it is a fixed array access.
-             */
-            string basetypestring = baseCompValu.type.ToString ();
-            if (basetypestring.EndsWith ("]")) {
-                TokenRVal subRVal = lVal.subRVal;
-                int nSubs = 1;
-                if (subRVal is TokenRValList) {
-                    nSubs   = ((TokenRValList)subRVal).nItems;
-                    subRVal = ((TokenRValList)subRVal).rVal;
-                }
-
-                int rank = basetypestring.IndexOf (']') - basetypestring.IndexOf ('[');
-                if (nSubs != rank) {
-                    ErrorMsg (lVal.baseRVal, "expect " + rank + " subscript" + ((rank == 1) ? "" : "s") + " but have " + nSubs);
-                }
-                CompValu[] subCompValus = new CompValu[rank];
-                int i;
-                for (i = 0; (subRVal != null) && (i < rank); i ++) {
-                    subCompValus[i] = GenerateFromRVal (subRVal);
-                    subRVal = (TokenRVal)subRVal.nextToken;
-                }
-                while (i < rank) subCompValus[i++] = new CompValuInteger (new TokenTypeInt (lVal.subRVal), 0);
-                return new CompValuFixArEl (this, baseCompValu, subCompValus);
-            }
-
-            /*
-             * Maybe it is accessing the $idxprop property of a script-defined class.
-             */
-            if (baseCompValu.type is TokenTypeSDTypeClass) {
-                TokenName name = new TokenName (lVal, "$idxprop");
-                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseCompValu.type;
-                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-                TokenDeclVar idxProp = FindThisMember (sdtDecl, name, null);
-                if (idxProp == null) {
-                    ErrorMsg (lVal, "no index property in class " + sdtDecl.longName.val);
-                    return new CompValuVoid (lVal);
-                }
-                if ((idxProp.sdtFlags & ScriptReduce.SDT_STATIC) != 0) {
-                    ErrorMsg (lVal, "non-static reference to static member " + idxProp.name.val);
-                    return new CompValuVoid (idxProp);
-                }
-                CheckAccess (idxProp, name);
-
-                TokenType[] argTypes = IdxPropArgTypes (idxProp);
-                CompValu[] compValus = IdxPropCompValus (lVal, argTypes.Length);
-                return new CompValuIdxProp (idxProp, baseCompValu, argTypes, compValus);
-
-            }
-
-            /*
-             * Maybe they are accessing $idxprop property of a script-defined interface.
-             */
-            if (baseCompValu.type is TokenTypeSDTypeInterface) {
-                TokenName name = new TokenName (lVal, "$idxprop");
-                TokenTypeSDTypeInterface sdtType = (TokenTypeSDTypeInterface)baseCompValu.type;
-                TokenDeclVar idxProp = FindInterfaceMember (sdtType, name, null, ref baseCompValu);
-                if (idxProp == null) {
-                    ErrorMsg (lVal, "no index property defined for interface " + sdtType.decl.longName.val);
-                    return baseCompValu;
-                }
-
-                TokenType[] argTypes = IdxPropArgTypes (idxProp);
-                CompValu[] compValus = IdxPropCompValus (lVal, argTypes.Length);
-                return new CompValuIdxProp (idxProp, baseCompValu, argTypes, compValus);
-            }
-
-            /*
-             * Maybe it is extracting a character from a string.
-             */
-            if ((baseCompValu.type is TokenTypeKey) || (baseCompValu.type is TokenTypeStr)) {
-                subCompValu = GenerateFromRVal (lVal.subRVal);
-                return new CompValuStrChr (new TokenTypeChar (lVal), baseCompValu, subCompValu);
-            }
-
-            /*
-             * Maybe it is extracting an element from a list.
-             */
-            if (baseCompValu.type is TokenTypeList) {
-                subCompValu = GenerateFromRVal (lVal.subRVal);
-                return new CompValuListEl (new TokenTypeObject (lVal), baseCompValu, subCompValu);
-            }
-
-            /*
-             * Access should be to XMR_Array otherwise.
-             */
-            if (!(baseCompValu.type is TokenTypeArray)) {
-                ErrorMsg (lVal, "taking subscript of non-array");
-                return baseCompValu;
-            }
-            subCompValu = GenerateFromRVal (lVal.subRVal);
-            return new CompValuArEle (new TokenTypeObject (lVal), baseCompValu, subCompValu);
-        }
-
-        /**
-         * @brief Get number and type of arguments required by an index property.
-         */
-        private static TokenType[] IdxPropArgTypes (TokenDeclVar idxProp)
-        {
-            TokenType[] argTypes;
-            if (idxProp.getProp != null) {
-                int nArgs = idxProp.getProp.argDecl.varDict.Count;
-                argTypes = new TokenType[nArgs];
-                foreach (TokenDeclVar var in idxProp.getProp.argDecl.varDict) {
-                    argTypes[var.vTableIndex] = var.type;
-                }
-            } else {
-                int nArgs = idxProp.setProp.argDecl.varDict.Count - 1;
-                argTypes = new TokenType[nArgs];
-                foreach (TokenDeclVar var in idxProp.setProp.argDecl.varDict) {
-                    if (var.vTableIndex < nArgs) {
-                        argTypes[var.vTableIndex] = var.type;
-                    }
-                }
-            }
-            return argTypes;
-        }
-
-        /**
-         * @brief Get number and computed value of index property arguments.
-         * @param lVal = list of arguments
-         * @param nArgs = number of arguments required
-         * @returns null: argument count mismatch
-         *          else: array of index property argument values
-         */
-        private CompValu[] IdxPropCompValus (TokenLValArEle lVal, int nArgs)
-        {
-            TokenRVal subRVal = lVal.subRVal;
-            int nSubs = 1;
-            if (subRVal is TokenRValList) {
-                nSubs   = ((TokenRValList)subRVal).nItems;
-                subRVal = ((TokenRValList)subRVal).rVal;
-            }
-
-            if (nSubs != nArgs) {
-                ErrorMsg (lVal, "index property requires " + nArgs + " subscript(s)");
-                return null;
-            }
-
-            CompValu[] subCompValus = new CompValu[nArgs];
-            for (int i = 0; i < nArgs; i ++) {
-                subCompValus[i] = GenerateFromRVal (subRVal);
-                subRVal = (TokenRVal)subRVal.nextToken;
-            }
-            return subCompValus;
-        }
-
-        /**
-         * @brief using 'base' within a script-defined instance method to refer to an instance field/method 
-         *        of the class being extended.
-         */
-        private CompValu GenerateFromLValBaseField (TokenLValBaseField baseField, TokenType[] argsig)
-        {
-            string fieldName = baseField.fieldName.val;
-
-            TokenDeclSDType sdtDecl = curDeclFunc.sdtClass;
-            if ((sdtDecl == null) || ((curDeclFunc.sdtFlags & ScriptReduce.SDT_STATIC) != 0)) {
-                ErrorMsg (baseField, "cannot use 'base' outside instance method body");
-                return new CompValuVoid (baseField);
-            }
-            if (!IsSDTInstMethod ()) {
-                ErrorMsg (baseField, "cannot access instance member of base class from static method");
-                return new CompValuVoid (baseField);
-            }
-
-            TokenDeclVar declVar = FindThisMember (sdtDecl.extends, baseField.fieldName, argsig);
-            if (declVar != null) {
-                CheckAccess (declVar, baseField.fieldName);
-                TokenType baseType = declVar.sdtClass.MakeRefToken (baseField);
-                CompValu  basePtr  = new CompValuArg (baseType, 0);
-                return AccessInstanceMember (declVar, basePtr, baseField, true);
-            }
-
-            ErrorMsg (baseField, "no member " + fieldName + ArgSigString (argsig) + " rootward of " + sdtDecl.longName.val);
-            return new CompValuVoid (baseField);
-        }
-
-        /**
-         * @brief We have an L-value token that is an instance field/method within a struct.
-         * @returns a CompValu giving the type and location of the field/method in the struct.
-         */
-        private CompValu GenerateFromLValIField (TokenLValIField lVal, TokenType[] argsig)
-        {
-            CompValu baseRVal = GenerateFromRVal (lVal.baseRVal);
-            string fieldName = lVal.fieldName.val + ArgSigString (argsig);
-
-            /*
-             * Maybe they are accessing an instance field, method or property of a script-defined class.
-             */
-            if (baseRVal.type is TokenTypeSDTypeClass) {
-                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
-                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-                TokenDeclVar declVar = FindThisMember (sdtDecl, lVal.fieldName, argsig);
-                if (declVar != null) {
-                    CheckAccess (declVar, lVal.fieldName);
-                    return AccessInstanceMember (declVar, baseRVal, lVal, false);
-                }
-                ErrorMsg (lVal.fieldName, "no member " + fieldName + " in class " + sdtDecl.longName.val);
-                return new CompValuVoid (lVal.fieldName);
-            }
-
-            /*
-             * Maybe they are accessing a method or property of a script-defined interface.
-             */
-            if (baseRVal.type is TokenTypeSDTypeInterface) {
-                TokenTypeSDTypeInterface sdtType = (TokenTypeSDTypeInterface)baseRVal.type;
-                TokenDeclVar declVar = FindInterfaceMember (sdtType, lVal.fieldName, argsig, ref baseRVal);
-                if (declVar != null) {
-                    return new CompValuIntfMember (declVar, baseRVal);
-                }
-                ErrorMsg (lVal.fieldName, "no member " + fieldName + " in interface " + sdtType.decl.longName.val);
-                return new CompValuVoid (lVal.fieldName);
-            }
-
-            /*
-             * Since we only have a few built-in types with fields, just pound them out.
-             */
-            if (baseRVal.type is TokenTypeArray) {
-
-                // no arguments, no parentheses, just the field name, returning integer
-                // but internally, it is a call to a method()
-                if (fieldName == "count") {
-                    return new CompValuIntInstROProp (tokenTypeInt, baseRVal, arrayCountMethodInfo);
-                }
-
-                // no arguments but with the parentheses, returning void
-                if (fieldName == "clear()") {
-                    return new CompValuIntInstMeth (XMR_Array.clearDelegate, baseRVal, arrayClearMethodInfo);
-                }
-
-                // single integer argument, returning an object
-                if (fieldName == "index(integer)") {
-                    return new CompValuIntInstMeth (XMR_Array.indexDelegate, baseRVal, arrayIndexMethodInfo);
-                }
-                if (fieldName == "value(integer)") {
-                    return new CompValuIntInstMeth (XMR_Array.valueDelegate, baseRVal, arrayValueMethodInfo);
-                }
-            }
-            if (baseRVal.type is TokenTypeRot) {
-                FieldInfo fi = null;
-                if (fieldName == "x") fi = rotationXFieldInfo;
-                if (fieldName == "y") fi = rotationYFieldInfo;
-                if (fieldName == "z") fi = rotationZFieldInfo;
-                if (fieldName == "s") fi = rotationSFieldInfo;
-                if (fi != null) {
-                    return new CompValuField (new TokenTypeFloat (lVal), baseRVal, fi);
-                }
-            }
-            if (baseRVal.type is TokenTypeVec) {
-                FieldInfo fi = null;
-                if (fieldName == "x") fi = vectorXFieldInfo;
-                if (fieldName == "y") fi = vectorYFieldInfo;
-                if (fieldName == "z") fi = vectorZFieldInfo;
-                if (fi != null) {
-                    return new CompValuField (new TokenTypeFloat (lVal), baseRVal, fi);
-                }
-            }
-
-            ErrorMsg (lVal, "type " + baseRVal.type.ToString () + " does not define member " + fieldName);
-            return baseRVal;
-        }
-
-        /**
-         * @brief We have an L-value token that is a function, method or variable name.
-         * @param lVal = name we are looking for
-         * @param argsig = null: just look for name as a variable
-         *                 else: look for name as a function/method being called with the given argument types
-         *                       eg, "(string,integer,list)"
-         * @returns a CompValu giving the type and location of the function, method or variable.
-         */
-        private CompValu GenerateFromLValName (TokenLValName lVal, TokenType[] argsig)
-        {
-            /*
-             * Look in variable stack then look for built-in constants and functions.
-             */
-            TokenDeclVar var = FindNamedVar (lVal, argsig);
-            if (var == null) {
-                ErrorMsg (lVal, "undefined constant/function/variable " + lVal.name.val + ArgSigString (argsig));
-                return new CompValuVoid (lVal);
-            }
-
-            /*
-             * Maybe it has an implied 'this.' on the front.
-             */
-            if ((var.sdtClass != null) && ((var.sdtFlags & ScriptReduce.SDT_STATIC) == 0)) {
-
-                if (!IsSDTInstMethod ()) {
-                    ErrorMsg (lVal, "cannot access instance member of class from static method");
-                    return new CompValuVoid (lVal);
-                }
-
-                /*
-                 * Don't allow something such as:
-                 *
-                 *    class A {
-                 *        integer I;
-                 *        class B {
-                 *            Print ()
-                 *            {
-                 *                llOwnerSay ("I=" + (string)I); <- access to I not allowed inside class B.
-                 *                                                  explicit reference required as we don't
-                 *                                                  have a valid reference to class A.
-                 *            }
-                 *        }
-                 *    }
-                 *
-                 * But do allow something such as:
-                 *
-                 *    class A {
-                 *        integer I;
-                 *    }
-                 *    class B : A {
-                 *        Print ()
-                 *        {
-                 *            llOwnerSay ("I=" + (string)I);
-                 *        }
-                 *    }
-                 */
-                for (TokenDeclSDType c = curDeclFunc.sdtClass; c != var.sdtClass; c = c.extends) {
-                    if (c == null) {
-                        // our arg0 points to an instance of curDeclFunc.sdtClass, not var.sdtClass
-                        ErrorMsg (lVal, "cannot access instance member of outer class with implied 'this'");
-                        break;
-                    }
-                }
-
-                CompValu thisCompValu = new CompValuArg (var.sdtClass.MakeRefToken (lVal), 0);
-                return AccessInstanceMember (var, thisCompValu, lVal, false);
-            }
-
-            /*
-             * It's a local variable, static field, global, constant, etc.
-             */
-            return var.location;
-        }
-
-        /**
-         * @brief Access a script-defined type's instance member
-         * @param declVar = which member (field,method,property) to access
-         * @param basePtr = points to particular object instance
-         * @param ignoreVirt = true: access declVar's method directly; else: maybe use vTable
-         * @returns where the field/method/property is located
-         */
-        private CompValu AccessInstanceMember (TokenDeclVar declVar, CompValu basePtr, Token errorAt, bool ignoreVirt)
-        {
-            if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0) {
-                ErrorMsg (errorAt, "non-static reference to static member " + declVar.name.val);
-                return new CompValuVoid (declVar);
-            }
-            return new CompValuInstMember (declVar, basePtr, ignoreVirt);
-        }
-
-        /**
-         * @brief we have an L-value token that is a static member within a struct.
-         * @returns a CompValu giving the type and location of the member in the struct.
-         */
-        private CompValu GenerateFromLValSField (TokenLValSField lVal, TokenType[] argsig)
-        {
-            TokenType stType = lVal.baseType;
-            string fieldName = lVal.fieldName.val + ArgSigString (argsig);
-
-            /*
-             * Maybe they are accessing a static member of a script-defined class.
-             */
-            if (stType is TokenTypeSDTypeClass) {
-                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)stType;
-                TokenDeclVar declVar = FindThisMember (sdtType.decl, lVal.fieldName, argsig);
-                if (declVar != null) {
-                    CheckAccess (declVar, lVal.fieldName);
-                    if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) == 0) {
-                        ErrorMsg (lVal.fieldName, "static reference to non-static member " + fieldName);
-                        return new CompValuVoid (lVal.fieldName);
-                    }
-                    return declVar.location;
-                }
-            }
-
-            ErrorMsg (lVal.fieldName, "no member " + fieldName + " in " + stType.ToString ());
-            return new CompValuVoid (lVal.fieldName);
-        }
-
-        /**
-         * @brief generate code from an RVal expression and return its type and where the result is stored.
-         * For anything that has side-effects, statements are generated that perform the computation then
-         * the result it put in a temp var and the temp var name is returned.
-         * For anything without side-effects, they are returned as an equivalent sequence of Emits.
-         * @param rVal = rVal token to be evaluated
-         * @param argsig = null: not being used in an function/method context
-         *                 else: string giving argument types, eg, "(string,integer,list,vector)"
-         *                       that can be used to select among overloaded methods
-         * @returns resultant type and location
-         */
-        private CompValu GenerateFromRVal (TokenRVal rVal)
-        {
-            return GenerateFromRVal (rVal, null);
-        }
-        private CompValu GenerateFromRVal (TokenRVal rVal, TokenType[] argsig)
-        {
-            errorMessageToken = rVal;
-
-            /*
-             * Maybe the expression can be converted to a constant.
-             */
-            bool didOne;
-            do {
-                didOne = false;
-                rVal = rVal.TryComputeConstant (LookupBodyConstants, ref didOne);
-            } while (didOne);
-
-            /*
-             * Generate code for the computation and return resulting type and location.
-             */
-            CompValu cVal = null;
-            if (rVal is TokenRValAsnPost)   cVal = GenerateFromRValAsnPost   ((TokenRValAsnPost)rVal);
-            if (rVal is TokenRValAsnPre)    cVal = GenerateFromRValAsnPre    ((TokenRValAsnPre)rVal);
-            if (rVal is TokenRValCall)      cVal = GenerateFromRValCall      ((TokenRValCall)rVal);
-            if (rVal is TokenRValCast)      cVal = GenerateFromRValCast      ((TokenRValCast)rVal);
-            if (rVal is TokenRValCondExpr)  cVal = GenerateFromRValCondExpr  ((TokenRValCondExpr)rVal);
-            if (rVal is TokenRValConst)     cVal = GenerateFromRValConst     ((TokenRValConst)rVal);
-            if (rVal is TokenRValInitDef)   cVal = GenerateFromRValInitDef   ((TokenRValInitDef)rVal);
-            if (rVal is TokenRValIsType)    cVal = GenerateFromRValIsType    ((TokenRValIsType)rVal);
-            if (rVal is TokenRValList)      cVal = GenerateFromRValList      ((TokenRValList)rVal);
-            if (rVal is TokenRValNewArIni)  cVal = GenerateFromRValNewArIni  ((TokenRValNewArIni)rVal);
-            if (rVal is TokenRValOpBin)     cVal = GenerateFromRValOpBin     ((TokenRValOpBin)rVal);
-            if (rVal is TokenRValOpUn)      cVal = GenerateFromRValOpUn      ((TokenRValOpUn)rVal);
-            if (rVal is TokenRValParen)     cVal = GenerateFromRValParen     ((TokenRValParen)rVal);
-            if (rVal is TokenRValRot)       cVal = GenerateFromRValRot       ((TokenRValRot)rVal);
-            if (rVal is TokenRValThis)      cVal = GenerateFromRValThis      ((TokenRValThis)rVal);
-            if (rVal is TokenRValUndef)     cVal = GenerateFromRValUndef     ((TokenRValUndef)rVal);
-            if (rVal is TokenRValVec)       cVal = GenerateFromRValVec       ((TokenRValVec)rVal);
-            if (rVal is TokenLVal)          cVal = GenerateFromLVal          ((TokenLVal)rVal, argsig);
-
-            if (cVal == null) throw new Exception ("bad rval class " + rVal.GetType ().ToString ());
-
-            /*
-             * Sanity check.
-             */
-            if (!youveAnError) {
-                if (cVal.type == null) throw new Exception ("cVal has no type " + cVal.GetType ());
-                string cValType = cVal.type.ToString ();
-                string rValType = rVal.GetRValType (this, argsig).ToString ();
-                if (cValType == "bool") cValType = "integer";
-                if (rValType == "bool") rValType = "integer";
-                if (cValType != rValType) {
-                    throw new Exception ("cVal.type " + cValType + " != rVal.type " + rValType +
-                                         "  (" + rVal.GetType ().Name + " " + rVal.SrcLoc + ")");
-                }
-            }
-
-            return cVal;
-        }
-
-        /**
-         * @brief compute the result of a binary operator (eg, add, subtract, multiply, lessthan)
-         * @param token = binary operator token, includes the left and right operands
-         * @returns where the resultant R-value is as something that doesn't have side effects
-         */
-        private CompValu GenerateFromRValOpBin (TokenRValOpBin token)
-        {
-            CompValu left, right;
-            string opcodeIndex = token.opcode.ToString ();
-
-            /*
-             * Comma operators are special, as they say to compute the left-hand value and 
-             * discard it, then compute the right-hand argument and that is the result.
-             */
-            if (opcodeIndex == ",") {
-
-                /*
-                 * Compute left-hand operand but throw away result.
-                 */
-                GenerateFromRVal (token.rValLeft);
-
-                /*
-                 * Compute right-hand operand and that is the value of the expression.
-                 */
-                return GenerateFromRVal (token.rValRight);
-            }
-
-            /*
-             * Simple overwriting assignments are their own special case,
-             * as we want to cast the R-value to the type of the L-value.
-             * And in the case of delegates, we want to use the arg signature
-             * of the delegate to select which overloaded method to use.
-             */
-            if (opcodeIndex == "=") {
-                if (!(token.rValLeft is TokenLVal)) {
-                    ErrorMsg (token, "invalid L-value for =");
-                    return GenerateFromRVal (token.rValLeft);
-                }
-                left  = GenerateFromLVal ((TokenLVal)token.rValLeft);
-                right = Trivialize (GenerateFromRVal (token.rValRight, left.GetArgTypes ()), token.rValRight);
-                left.PopPre (this, token.rValLeft);
-                right.PushVal (this, token.rValRight, left.type);  // push (left.type)right
-                left.PopPost (this, token.rValLeft);               // pop to left
-                return left;
-            }
-
-            /*
-             * There are String.Concat() methods available for 2, 3 and 4 operands.
-             * So see if we have a string concat op and optimize if so.
-             */
-            if ((opcodeIndex == "+") || 
-                ((opcodeIndex == "+=") && 
-                 (token.rValLeft is TokenLVal) && 
-                 (token.rValLeft.GetRValType (this, null) is TokenTypeStr))) {
-
-                /*
-                 * We are adding something.  Maybe it's a bunch of strings together.
-                 */
-                List<TokenRVal> scorvs = new List<TokenRVal> ();
-                if (StringConcatOperands (token.rValLeft, token.rValRight, scorvs, token.opcode)) {
-
-                    /*
-                     * Evaluate all the operands, right-to-left on purpose per LSL scripting.
-                     */
-                    int i;
-                    int n = scorvs.Count;
-                    CompValu[] scocvs = new CompValu[n];
-                    for (i = n; -- i >= 0;) {
-                        scocvs[i] = GenerateFromRVal (scorvs[i]);
-                        if (i > 0) scocvs[i] = Trivialize (scocvs[i], scorvs[i]);
-                    }
-
-                    /*
-                     * Figure out where to put the result.
-                     * A temp if '+', or back in original L-value if '+='.
-                     */
-                    CompValu retcv;
-                    if (opcodeIndex == "+") {
-                        retcv = new CompValuTemp (new TokenTypeStr (token.opcode), this);
-                    } else {
-                        retcv = GenerateFromLVal ((TokenLVal)token.rValLeft);
-                    }
-                    retcv.PopPre (this, token);
-
-                    /*
-                     * Call the String.Concat() methods, passing operands in left-to-right order.
-                     * Force a cast to string (retcv.type) for each operand.
-                     */
-                    ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                    while (i + 3 < n) {
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ilGen.Emit (scorvs[i], OpCodes.Call, stringConcat4MethodInfo);
-                    }
-                    if (i + 2 < n) {
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ilGen.Emit (scorvs[i], OpCodes.Call, stringConcat3MethodInfo);
-                    }
-                    if (i + 1 < n) {
-                        ++ i; scocvs[i].PushVal (this, scorvs[i], retcv.type);
-                        ilGen.Emit (scorvs[i], OpCodes.Call, stringConcat2MethodInfo);
-                    }
-
-                    /*
-                     * Put the result where we want it and return where we put it.
-                     */
-                    retcv.PopPost (this, token);
-                    return retcv;
-                }
-            }
-
-            /*
-             * If "&&&", it is a short-circuiting AND.
-             * Compute left-hand operand and if true, compute right-hand operand.
-             */
-            if (opcodeIndex == "&&&") {
-                bool leftVal, rightVal;
-                left = GenerateFromRVal (token.rValLeft);
-                if (!IsConstBoolExpr (left, out leftVal)) {
-                    ScriptMyLabel falseLabel = ilGen.DefineLabel ("ssandfalse");
-                    left.PushVal (this, tokenTypeBool);
-                    ilGen.Emit (token, OpCodes.Brfalse, falseLabel);
-                    right = GenerateFromRVal (token.rValRight);
-                    if (!IsConstBoolExpr (right, out rightVal)) {
-                        right.PushVal (this, tokenTypeBool);
-                        goto donessand;
-                    }
-                    if (!rightVal) {
-                        ilGen.MarkLabel (falseLabel);
-                        return new CompValuInteger (new TokenTypeInt (token.rValLeft), 0);
-                    }
-                    ilGen.Emit (token, OpCodes.Ldc_I4_1);
-                donessand:
-                    ScriptMyLabel doneLabel = ilGen.DefineLabel ("ssanddone");
-                    ilGen.Emit (token, OpCodes.Br, doneLabel);
-                    ilGen.MarkLabel (falseLabel);
-                    ilGen.Emit (token, OpCodes.Ldc_I4_0);
-                    ilGen.MarkLabel (doneLabel);
-                    CompValuTemp retRVal = new CompValuTemp (new TokenTypeInt (token), this);
-                    retRVal.Pop (this, token);
-                    return retRVal;
-                }
-
-                if (!leftVal) {
-                    return new CompValuInteger (new TokenTypeInt (token.rValLeft), 0);
-                }
-
-                right = GenerateFromRVal (token.rValRight);
-                if (!IsConstBoolExpr (right, out rightVal)) {
-                    right.PushVal (this, tokenTypeBool);
-                    CompValuTemp retRVal = new CompValuTemp (new TokenTypeInt (token), this);
-                    retRVal.Pop (this, token);
-                    return retRVal;
-                }
-                return new CompValuInteger (new TokenTypeInt (token), rightVal ? 1 : 0);
-            }
-
-            /*
-             * If "|||", it is a short-circuiting OR.
-             * Compute left-hand operand and if false, compute right-hand operand.
-             */
-            if (opcodeIndex == "|||") {
-                bool leftVal, rightVal;
-                left = GenerateFromRVal (token.rValLeft);
-                if (!IsConstBoolExpr (left, out leftVal)) {
-                    ScriptMyLabel trueLabel = ilGen.DefineLabel ("ssortrue");
-                    left.PushVal (this, tokenTypeBool);
-                    ilGen.Emit (token, OpCodes.Brtrue, trueLabel);
-                    right = GenerateFromRVal (token.rValRight);
-                    if (!IsConstBoolExpr (right, out rightVal)) {
-                        right.PushVal (this, tokenTypeBool);
-                        goto donessor;
-                    }
-                    if (rightVal) {
-                        ilGen.MarkLabel (trueLabel);
-                        return new CompValuInteger (new TokenTypeInt (token.rValLeft), 1);
-                    }
-                    ilGen.Emit (token, OpCodes.Ldc_I4_0);
-                donessor:
-                    ScriptMyLabel doneLabel = ilGen.DefineLabel ("ssanddone");
-                    ilGen.Emit (token, OpCodes.Br, doneLabel);
-                    ilGen.MarkLabel (trueLabel);
-                    ilGen.Emit (token, OpCodes.Ldc_I4_1);
-                    ilGen.MarkLabel (doneLabel);
-                    CompValuTemp retRVal = new CompValuTemp (new TokenTypeInt (token), this);
-                    retRVal.Pop (this, token);
-                    return retRVal;
-                }
-
-                if (leftVal) {
-                    return new CompValuInteger (new TokenTypeInt (token.rValLeft), 1);
-                }
-
-                right = GenerateFromRVal (token.rValRight);
-                if (!IsConstBoolExpr (right, out rightVal)) {
-                    right.PushVal (this, tokenTypeBool);
-                    CompValuTemp retRVal = new CompValuTemp (new TokenTypeInt (token), this);
-                    retRVal.Pop (this, token);
-                    return retRVal;
-                }
-                return new CompValuInteger (new TokenTypeInt (token), rightVal ? 1 : 0);
-            }
-
-            /*
-             * Computation of some sort, compute right-hand operand value then left-hand value
-             * because LSL is supposed to be right-to-left evaluation.
-             */
-            right = Trivialize (GenerateFromRVal (token.rValRight), token.rValRight);
-
-            /*
-             * If left is a script-defined class and there is a method with the operator's name,
-             * convert this to a call to that method with the right value as its single parameter.
-             * Except don't if the right value is 'undef' so they can always compare to undef.
-             */
-            TokenType leftType = token.rValLeft.GetRValType (this, null);
-            if ((leftType is TokenTypeSDTypeClass) && !(right.type is TokenTypeUndef)) {
-                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)leftType;
-                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-                TokenType[] argsig = new TokenType[] { right.type };
-                TokenName funcName = new TokenName (token.opcode, "$op" + opcodeIndex);
-                TokenDeclVar declFunc = FindThisMember (sdtDecl, funcName, argsig);
-                if (declFunc != null) {
-                    CheckAccess (declFunc, funcName);
-                    left = GenerateFromRVal (token.rValLeft);
-                    CompValu method = AccessInstanceMember (declFunc, left, token, false);
-                    CompValu[] argRVals = new CompValu[] { right };
-                    return GenerateACall (method, argRVals, token);
-                }
-            }
-
-            /*
-             * Formulate key string for binOpStrings = (lefttype)(operator)(righttype)
-             */
-            string leftIndex = leftType.ToString ();
-            string rightIndex = right.type.ToString ();
-            string key = leftIndex + opcodeIndex + rightIndex;
-
-            /*
-             * If that key exists in table, then the operation is defined between those types
-             * ... and it produces an R-value of type as given in the table.
-             */
-            BinOpStr binOpStr;
-            if (BinOpStr.defined.TryGetValue (key, out binOpStr)) {
-
-                /*
-                 * If table contained an explicit assignment type like +=, output the statement without
-                 * casting the L-value, then return the L-value as the resultant value.
-                 *
-                 * Make sure we don't include comparisons (such as ==, >=, etc).
-                 * Nothing like +=, -=, %=, etc, generate a boolean, only the comparisons.
-                 */
-                if ((binOpStr.outtype != typeof (bool)) && opcodeIndex.EndsWith ("=") && (opcodeIndex != "!=")) {
-                    if (!(token.rValLeft is TokenLVal)) {
-                        ErrorMsg (token.rValLeft, "invalid L-value");
-                        return GenerateFromRVal (token.rValLeft);
-                    }
-                    left = GenerateFromLVal ((TokenLVal)token.rValLeft);
-                    binOpStr.emitBO (this, token, left, right, left);
-                    return left;
-                }
-
-                /*
-                 * It's of the form left binop right.
-                 * Compute left, perform operation then put result in a temp.
-                 */
-                left = GenerateFromRVal (token.rValLeft);
-                CompValu retRVal = new CompValuTemp (TokenType.FromSysType (token.opcode, binOpStr.outtype), this);
-                binOpStr.emitBO (this, token, left, right, retRVal);
-                return retRVal;
-            }
-
-            /*
-             * Nothing in the table, check for comparing object pointers because of the myriad of types possible.
-             * This will compare list pointers, null pointers, script-defined type pointers, array pointers, etc.
-             * It will show equal iff the memory addresses are equal and that is good enough.
-             */
-            if (!leftType.ToSysType().IsValueType && !right.type.ToSysType().IsValueType && ((opcodeIndex == "==") || (opcodeIndex == "!="))) {
-                CompValuTemp retRVal = new CompValuTemp (new TokenTypeInt (token), this);
-                left = GenerateFromRVal (token.rValLeft);
-                left.PushVal (this, token.rValLeft);
-                right.PushVal (this, token.rValRight);
-                ilGen.Emit (token, OpCodes.Ceq);
-                if (opcodeIndex == "!=") {
-                    ilGen.Emit (token, OpCodes.Ldc_I4_1);
-                    ilGen.Emit (token, OpCodes.Xor);
-                }
-                retRVal.Pop (this, token);
-                return retRVal;
-            }
-
-            /*
-             * If the opcode ends with "=", it may be something like "+=".
-             * So look up the key as if we didn't have the "=" to tell us if the operation is legal.
-             * Also, the binary operation's output type must be the same as the L-value type.
-             * Likewise, integer += float not allowed because result is float, but float += integer is ok.
-             */
-            if (opcodeIndex.EndsWith ("=")) {
-                key = leftIndex + opcodeIndex.Substring (0, opcodeIndex.Length - 1) + rightIndex;
-                if (BinOpStr.defined.TryGetValue (key, out binOpStr)) {
-                    if (!(token.rValLeft is TokenLVal)) {
-                        ErrorMsg (token, "invalid L-value for <op>=");
-                        return GenerateFromRVal (token.rValLeft);
-                    }
-                    if (!binOpStr.rmwOK) {
-                        ErrorMsg (token, "<op>= not allowed: " + leftIndex + " " + opcodeIndex + " " + rightIndex);
-                        return new CompValuVoid (token);
-                    }
-
-                    /*
-                     * Now we know for something like %= that left%right is legal for the types given.
-                     */
-                    left = GenerateFromLVal ((TokenLVal)token.rValLeft);
-                    if (binOpStr.outtype == leftType.ToSysType ()) {
-                        binOpStr.emitBO (this, token, left, right, left);
-                    } else {
-                        CompValu temp = new CompValuTemp (TokenType.FromSysType (token, binOpStr.outtype), this);
-                        binOpStr.emitBO (this, token, left, right, temp);
-                        left.PopPre (this, token);
-                        temp.PushVal (this, token, leftType);
-                        left.PopPost (this, token);
-                    }
-                    return left;
-                }
-            }
-
-            /*
-             * Can't find it, oh well.
-             */
-            ErrorMsg (token, "op not defined: " + leftIndex + " " + opcodeIndex + " " + rightIndex);
-            return new CompValuVoid (token);
-        }
-
-        /**
-         * @brief Queue the given operands to the end of the scos list.
-         *        If it can be broken down into more string concat operands, do so.
-         *        Otherwise, just push it as one operand.
-         * @param leftRVal  = left-hand operand of a '+' operation
-         * @param rightRVal = right-hand operand of a '+' operation
-         * @param scos      = left-to-right list of operands for the string concat so far
-         * @param addop     = the add operator token (either '+' or '+=')
-         * @returns false: neither operand is a string, nothing added to scos
-         *           true: scos = updated with leftRVal then rightRVal added onto the end, possibly broken down further
-         */
-        private bool StringConcatOperands (TokenRVal leftRVal, TokenRVal rightRVal, List<TokenRVal> scos, TokenKw addop)
-        {
-            /*
-             * If neither operand is a string (eg, float+integer), then the result isn't going to be a string.
-             */
-            TokenType leftType  = leftRVal.GetRValType  (this, null);
-            TokenType rightType = rightRVal.GetRValType (this, null);
-            if (!(leftType is TokenTypeStr) && !(rightType is TokenTypeStr)) return false;
-
-            /*
-             * Also, list+string => list so reject that too.
-             * Also, string+list => list so reject that too.
-             */
-            if (leftType  is TokenTypeList) return false;
-            if (rightType is TokenTypeList) return false;
-
-            /*
-             * Append values to the end of the list in left-to-right order.
-             * If value is formed from a something+something => string, 
-             * push them as separate values, otherwise push as one value.
-             */
-            StringConcatOperand (leftType,  leftRVal,  scos);
-            StringConcatOperand (rightType, rightRVal, scos);
-
-            /*
-             * Maybe constant strings can be concatted.
-             */
-            try {
-                int len;
-                while (((len = scos.Count) >= 2) && 
-                       ((leftRVal  = scos[len-2]) is TokenRValConst) && 
-                       ((rightRVal = scos[len-1]) is TokenRValConst)) {
-                    object sum = addop.binOpConst (((TokenRValConst)leftRVal).val, 
-                                                   ((TokenRValConst)rightRVal).val);
-                    scos[len-2] = new TokenRValConst (addop, sum);
-                    scos.RemoveAt (len - 1);
-                }
-            } catch {
-            }
-
-            /*
-             * We pushed some string stuff.
-             */
-            return true;
-        }
-
-        /**
-         * @brief Queue the given operand to the end of the scos list.
-         *        If it can be broken down into more string concat operands, do so.
-         *        Otherwise, just push it as one operand.
-         * @param type = rVal's resultant type
-         * @param rVal = operand to examine
-         * @param scos = left-to-right list of operands for the string concat so far
-         * @returns with scos = updated with rVal added onto the end, possibly broken down further
-         */
-        private void StringConcatOperand (TokenType type, TokenRVal rVal, List<TokenRVal> scos)
-        {
-            bool didOne;
-            do {
-                didOne = false;
-                rVal   = rVal.TryComputeConstant (LookupBodyConstants, ref didOne);
-            } while (didOne);
-
-            if (!(type is TokenTypeStr)) goto pushasis;
-            if (!(rVal is TokenRValOpBin)) goto pushasis;
-            TokenRValOpBin rValOpBin = (TokenRValOpBin)rVal;
-            if (!(rValOpBin.opcode is TokenKwAdd)) goto pushasis;
-            if (StringConcatOperands (rValOpBin.rValLeft, rValOpBin.rValRight, scos, rValOpBin.opcode)) return;
-            pushasis:
-            scos.Add (rVal);
-        }
-
-        /**
-         * @brief compute the result of an unary operator
-         * @param token = unary operator token, includes the operand
-         * @returns where the resultant R-value is
-         */
-        private CompValu GenerateFromRValOpUn (TokenRValOpUn token)
-        {
-            CompValu inRVal = GenerateFromRVal (token.rVal);
-
-            /*
-             * Script-defined types can define their own methods to handle unary operators.
-             */
-            if (inRVal.type is TokenTypeSDTypeClass) {
-                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)inRVal.type;
-                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-                TokenName funcName = new TokenName (token.opcode, "$op" + token.opcode.ToString ());
-                TokenDeclVar declFunc = FindThisMember (sdtDecl, funcName, zeroArgs);
-                if (declFunc != null) {
-                    CheckAccess (declFunc, funcName);
-                    CompValu method = AccessInstanceMember (declFunc, inRVal, token, false);
-                    return GenerateACall (method, zeroCompValus, token);
-                }
-            }
-
-            /*
-             * Otherwise use the default.
-             */
-            return UnOpGenerate (inRVal, token.opcode);
-        }
-
-        /**
-         * @brief postfix operator -- this returns the type and location of the resultant value
-         */
-        private CompValu GenerateFromRValAsnPost (TokenRValAsnPost asnPost)
-        {
-            CompValu lVal = GenerateFromLVal (asnPost.lVal);
-
-            /*
-             * Make up a temp to save original value in.
-             */
-            CompValuTemp result = new CompValuTemp (lVal.type, this);
-
-            /*
-             * Prepare to pop incremented value back into variable being incremented.
-             */
-            lVal.PopPre (this, asnPost.lVal);
-
-            /*
-             * Copy original value to temp and leave value on stack.
-             */
-            lVal.PushVal (this, asnPost.lVal);
-            ilGen.Emit (asnPost.lVal, OpCodes.Dup);
-            result.Pop (this, asnPost.lVal);
-
-            /*
-             * Perform the ++/--.
-             */
-            if ((lVal.type is TokenTypeChar) || (lVal.type is TokenTypeInt)) {
-                ilGen.Emit (asnPost, OpCodes.Ldc_I4_1);
-            } else if (lVal.type is TokenTypeFloat) {
-                ilGen.Emit (asnPost, OpCodes.Ldc_R4, 1.0f);
-            } else {
-                lVal.PopPost (this, asnPost.lVal);
-                ErrorMsg (asnPost, "invalid type for " + asnPost.postfix.ToString ());
-                return lVal;
-            }
-            switch (asnPost.postfix.ToString ()) {
-                case "++": {
-                    ilGen.Emit (asnPost, OpCodes.Add);
-                    break;
-                }
-                case "--": {
-                    ilGen.Emit (asnPost, OpCodes.Sub);
-                    break;
-                }
-                default: throw new Exception ("unknown asnPost op");
-            }
-
-            /*
-             * Store new value in original variable.
-             */
-            lVal.PopPost (this, asnPost.lVal);
-
-            return result;
-        }
-
-        /**
-         * @brief prefix operator -- this returns the type and location of the resultant value
-         */
-        private CompValu GenerateFromRValAsnPre (TokenRValAsnPre asnPre)
-        {
-            CompValu lVal = GenerateFromLVal (asnPre.lVal);
-
-            /*
-             * Make up a temp to put result in.
-             */
-            CompValuTemp result = new CompValuTemp (lVal.type, this);
-
-            /*
-             * Prepare to pop incremented value back into variable being incremented.
-             */
-            lVal.PopPre (this, asnPre.lVal);
-
-            /*
-             * Push original value.
-             */
-            lVal.PushVal (this, asnPre.lVal);
-
-            /*
-             * Perform the ++/--.
-             */
-            if ((lVal.type is TokenTypeChar) || (lVal.type is TokenTypeInt)) {
-                ilGen.Emit (asnPre, OpCodes.Ldc_I4_1);
-            } else if (lVal.type is TokenTypeFloat) {
-                ilGen.Emit (asnPre, OpCodes.Ldc_R4, 1.0f);
-            } else {
-                lVal.PopPost (this, asnPre.lVal);
-                ErrorMsg (asnPre, "invalid type for " + asnPre.prefix.ToString ());
-                return lVal;
-            }
-            switch (asnPre.prefix.ToString ()) {
-                case "++": {
-                    ilGen.Emit (asnPre, OpCodes.Add);
-                    break;
-                }
-                case "--": {
-                    ilGen.Emit (asnPre, OpCodes.Sub);
-                    break;
-                }
-                default: throw new Exception ("unknown asnPre op");
-            }
-
-            /*
-             * Store new value in temp variable, keeping new value on stack.
-             */
-            ilGen.Emit (asnPre.lVal, OpCodes.Dup);
-            result.Pop (this, asnPre.lVal);
-
-            /*
-             * Store new value in original variable.
-             */
-            lVal.PopPost (this, asnPre.lVal);
-
-            return result;
-        }
-
-        /**
-         * @brief Generate code that calls a function or object's method.
-         * @returns where the call's return value is stored (a TokenTypeVoid if void)
-         */
-        private CompValu GenerateFromRValCall (TokenRValCall call)
-        {
-            CompValu method;
-            CompValu[] argRVals;
-            int i, nargs;
-            TokenRVal arg;
-            TokenType[] argTypes;
-
-            /*
-             * Compute the values of all the function's call arguments.
-             * Save where the computation results are in the argRVals[] array.
-             * Might as well build the argument signature from the argument types, too.
-             */
-            nargs = call.nArgs;
-            argRVals = new CompValu[nargs];
-            argTypes = new TokenType[nargs];
-            if (nargs > 0) {
-                i = 0;
-                for (arg = call.args; arg != null; arg = (TokenRVal)arg.nextToken) {
-                    argRVals[i] = GenerateFromRVal (arg);
-                    argTypes[i] = argRVals[i].type;
-                    i ++;
-                }
-            }
-
-            /*
-             * Get function/method's entrypoint that matches the call argument types.
-             */
-            method = GenerateFromRVal (call.meth, argTypes);
-            if (method == null) return null;
-
-            return GenerateACall (method, argRVals, call);
-        }
-
-        /**
-         * @brief Generate call to a function/method.
-         * @param method = function/method being called
-         * @param argVRVals = its call parameters (zero length if none)
-         * @param call = where in source code call is being made from (for error messages)
-         * @returns type and location of return value (CompValuVoid if none)
-         */
-        private CompValu GenerateACall (CompValu method, CompValu[] argRVals, Token call)
-        {
-            CompValuTemp result;
-            int i, nArgs;
-            TokenType retType;
-            TokenType[] argTypes;
-
-            /*
-             * Must be some kind of callable.
-             */
-            retType = method.GetRetType ();  // TokenTypeVoid if void; null means a variable
-            if (retType == null) {
-                ErrorMsg (call, "must be a delegate, function or method");
-                return new CompValuVoid (call);
-            }
-
-            /*
-             * Get a location for return value.
-             */
-            if (retType is TokenTypeVoid) {
-                result = new CompValuVoid (call);
-            } else {
-                result = new CompValuTemp (retType, this);
-            }
-
-            /*
-             * Make sure all arguments are trivial, ie, don't involve their own call labels.
-             * For any that aren't, output code to calculate the arg and put in a temporary.
-             */
-            nArgs = argRVals.Length;
-            for (i = 0; i < nArgs; i ++) {
-                if (!argRVals[i].IsReadTrivial (this, call)) {
-                    argRVals[i] = Trivialize (argRVals[i], call);
-                }
-            }
-
-            /*
-             * Inline functions know how to generate their own call.
-             */
-            if (method is CompValuInline) {
-                CompValuInline inline = (CompValuInline)method;
-                inline.declInline.CodeGen (this, call, result, argRVals);
-                return result;
-            }
-
-            /*
-             * Push whatever the function/method needs as a this argument, if anything.
-             */
-            method.CallPre (this, call);
-
-            /*
-             * Push the script-visible args, left-to-right.
-             */
-            argTypes = method.GetArgTypes ();
-            for (i = 0; i < nArgs; i ++) {
-                if (argTypes == null) {
-                    argRVals[i].PushVal (this, call);
-                } else {
-                    argRVals[i].PushVal (this, call, argTypes[i]);
-                }
-            }
-
-            /*
-             * Now output call instruction.
-             */
-            method.CallPost (this, call);
-
-            /*
-             * Deal with the return value (if any), by putting it in 'result'.
-             */
-            result.Pop (this, call, retType);
-            return result;
-        }
-
-        /**
-         * @brief This is needed to avoid nesting call labels around non-trivial properties.
-         *        It should be used for the second (and later) operands.
-         *        Note that a 'call' is considered an operator, so all arguments of a call
-         *        should be trivialized, but the method itself does not need to be.
-         */
-        public CompValu Trivialize (CompValu operand, Token errorAt)
-        {
-            if (operand.IsReadTrivial (this, errorAt)) return operand;
-            CompValuTemp temp = new CompValuTemp (operand.type, this);
-            operand.PushVal (this, errorAt);
-            temp.Pop (this, errorAt);
-            return temp;
-        }
-
-        /**
-         * @brief Generate code that casts a value to a particular type.
-         * @returns where the result of the conversion is stored.
-         */
-        private CompValu GenerateFromRValCast (TokenRValCast cast)
-        {
-            /*
-             * If casting to a delegate type, use the argment signature 
-             * of the delegate to help select the function/method, eg, 
-             *    '(delegate string(integer))ToString'
-             * will select 'string ToString(integer x)'
-             * instaead of 'string ToString(float x)' or anything else
-             */
-            TokenType[] argsig = null;
-            TokenType outType = cast.castTo;
-            if (outType is TokenTypeSDTypeDelegate) {
-                argsig = ((TokenTypeSDTypeDelegate)outType).decl.GetArgTypes ();
-            }
-
-            /*
-             * Generate the value that is being cast.
-             * If the value is already the requested type, just use it as is.
-             */
-            CompValu inRVal = GenerateFromRVal (cast.rVal, argsig);
-            if (inRVal.type == outType) return inRVal;
-
-            /*
-             * Different type, generate casting code, putting the result in a temp of the output type.
-             */
-            CompValu outRVal = new CompValuTemp (outType, this);
-            outRVal.PopPre (this, cast);
-            inRVal.PushVal (this, cast, outType, true);
-            outRVal.PopPost (this, cast);
-            return outRVal;
-        }
-
-        /**
-         * @brief Compute conditional expression value.
-         * @returns type and location of computed value.
-         */
-        private CompValu GenerateFromRValCondExpr (TokenRValCondExpr rValCondExpr)
-        {
-            bool condVal;
-            CompValu condValu = GenerateFromRVal (rValCondExpr.condExpr);
-            if (IsConstBoolExpr (condValu, out condVal)) {
-                return GenerateFromRVal (condVal ? rValCondExpr.trueExpr : rValCondExpr.falseExpr);
-            }
-
-            ScriptMyLabel falseLabel = ilGen.DefineLabel ("condexfalse");
-            ScriptMyLabel doneLabel  = ilGen.DefineLabel ("condexdone");
-
-            condValu.PushVal (this, rValCondExpr.condExpr, tokenTypeBool);
-            ilGen.Emit (rValCondExpr, OpCodes.Brfalse, falseLabel);
-
-            CompValu trueValu = GenerateFromRVal (rValCondExpr.trueExpr);
-            trueValu.PushVal (this, rValCondExpr.trueExpr);
-            ilGen.Emit (rValCondExpr, OpCodes.Br, doneLabel);
-
-            ilGen.MarkLabel (falseLabel);
-            CompValu falseValu = GenerateFromRVal (rValCondExpr.falseExpr);
-            falseValu.PushVal (this, rValCondExpr.falseExpr);
-
-            if (trueValu.type.GetType () != falseValu.type.GetType ()) {
-                ErrorMsg (rValCondExpr, "? operands " + trueValu.type.ToString () + " : " +
-                              falseValu.type.ToString () + " must be of same type");
-            }
-
-            ilGen.MarkLabel (doneLabel);
-            CompValuTemp retRVal = new CompValuTemp (trueValu.type, this);
-            retRVal.Pop (this, rValCondExpr);
-            return retRVal;
-        }
-
-        /**
-         * @brief Constant in the script somewhere
-         * @returns where the constants value is stored
-         */
-        private CompValu GenerateFromRValConst (TokenRValConst rValConst)
-        {
-            switch (rValConst.type) {
-                case TokenRValConstType.CHAR: {
-                    return new CompValuChar (new TokenTypeChar (rValConst), (char)(rValConst.val));
-                }
-                case TokenRValConstType.FLOAT: {
-                    return new CompValuFloat (new TokenTypeFloat (rValConst), (double)(rValConst.val));
-                }
-                case TokenRValConstType.INT: {
-                    return new CompValuInteger (new TokenTypeInt (rValConst), (int)(rValConst.val));
-                }
-                case TokenRValConstType.KEY: {
-                    return new CompValuString (new TokenTypeKey (rValConst), (string)(rValConst.val));
-                }
-                case TokenRValConstType.STRING: {
-                    return new CompValuString (new TokenTypeStr (rValConst), (string)(rValConst.val));
-                }
-            }
-            throw new Exception ("unknown constant type " + rValConst.val.GetType ());
-        }
-
-        /**
-         * @brief generate a new list object
-         * @param rValList = an rVal to create it from
-         */
-        private CompValu GenerateFromRValList (TokenRValList rValList)
-        {
-            /*
-             * Compute all element values and remember where we put them.
-             * Do it right-to-left as customary for LSL scripts.
-             */
-            int i = 0;
-            TokenRVal lastRVal = null;
-            for (TokenRVal val = rValList.rVal; val != null; val = (TokenRVal)val.nextToken) {
-                i ++;
-                val.prevToken = lastRVal;
-                lastRVal = val;
-            }
-            CompValu[] vals = new CompValu[i];
-            for (TokenRVal val = lastRVal; val != null; val = (TokenRVal)val.prevToken) {
-                vals[--i] = GenerateFromRVal (val);
-            }
-
-            /*
-             * This is the temp that will hold the created list.
-             */
-            CompValuTemp newList = new CompValuTemp (new TokenTypeList (rValList.rVal), this);
-
-            /*
-             * Create a temp object[] array to hold all the initial values.
-             */
-            ilGen.Emit (rValList, OpCodes.Ldc_I4, rValList.nItems);
-            ilGen.Emit (rValList, OpCodes.Newarr, typeof (object));
-
-            /*
-             * Populate the array.
-             */
-            i = 0;
-            for (TokenRVal val = rValList.rVal; val != null; val = (TokenRVal)val.nextToken) {
-
-                /*
-                 * Get pointer to temp array object.
-                 */
-                ilGen.Emit (rValList, OpCodes.Dup);
-
-                /*
-                 * Get index in that array.
-                 */
-                ilGen.Emit (rValList, OpCodes.Ldc_I4, i);
-
-                /*
-                 * Store initialization value in array location.
-                 * However, floats and ints need to be converted to LSL_Float and LSL_Integer,
-                 * or things like llSetPayPrice() will puque when they try to cast the elements
-                 * to LSL_Float or LSL_Integer.  Likewise with string/LSL_String.
-                 *
-                 * Maybe it's already LSL-boxed so we don't do anything with it except make sure
-                 * it is an object, not a struct.
-                 */
-                CompValu eRVal = vals[i++];
-                eRVal.PushVal (this, val);
-                if (eRVal.type.ToLSLWrapType () == null) {
-                    if (eRVal.type is TokenTypeFloat) {
-                        ilGen.Emit (val, OpCodes.Newobj, lslFloatConstructorInfo);
-                        ilGen.Emit (val, OpCodes.Box, typeof (LSL_Float));
-                    } else if (eRVal.type is TokenTypeInt) {
-                        ilGen.Emit (val, OpCodes.Newobj, lslIntegerConstructorInfo);
-                        ilGen.Emit (val, OpCodes.Box, typeof (LSL_Integer));
-                    } else if ((eRVal.type is TokenTypeKey) || (eRVal.type is TokenTypeStr)) {
-                        ilGen.Emit (val, OpCodes.Newobj, lslStringConstructorInfo);
-                        ilGen.Emit (val, OpCodes.Box, typeof (LSL_String));
-                    } else if (eRVal.type.ToSysType ().IsValueType) {
-                        ilGen.Emit (val, OpCodes.Box, eRVal.type.ToSysType ());
-                    }
-                } else if (eRVal.type.ToLSLWrapType ().IsValueType) {
-
-                    // Convert the LSL value structs to an object of the LSL-boxed type
-                    ilGen.Emit (val, OpCodes.Box, eRVal.type.ToLSLWrapType ());
-                }
-                ilGen.Emit (val, OpCodes.Stelem, typeof (object));
-            }
-
-            /*
-             * Create new list object from temp initial value array (whose ref is still on the stack).
-             */
-            ilGen.Emit (rValList, OpCodes.Newobj, lslListConstructorInfo);
-            newList.Pop (this, rValList);
-            return newList;
-        }
-
-        /**
-         * @brief New array allocation with initializer expressions.
-         */
-        private CompValu GenerateFromRValNewArIni (TokenRValNewArIni rValNewArIni)
-        {
-            return MallocAndInitArray (rValNewArIni.arrayType, rValNewArIni.valueList);
-        }
-
-        /**
-         * @brief Mallocate and initialize an array from its initialization list.
-         * @param arrayType = type of the array to be allocated and initialized
-         * @param values    = initialization value list used to size and initialize the array.
-         * @returns memory location of the resultant initialized array.
-         */
-        private CompValu MallocAndInitArray (TokenType arrayType, TokenList values)
-        {
-            TokenDeclSDTypeClass arrayDecl = ((TokenTypeSDTypeClass)arrayType).decl;
-            TokenType eleType = arrayDecl.arrayOfType;
-            int rank = arrayDecl.arrayOfRank;
-
-            // Get size of each of the dimensions by scanning the initialization value list
-            int[] dimSizes = new int[rank];
-            FillInDimSizes (dimSizes, 0, rank, values);
-
-            // Figure out where the array's $new() method is
-            TokenType[] newargsig = new TokenType[rank];
-            for (int k = 0; k < rank; k ++) {
-                newargsig[k] = tokenTypeInt;
-            }
-            TokenDeclVar newMeth = FindThisMember (arrayDecl, new TokenName (null, "$new"), newargsig);
-
-            // Output a call to malloc the array with all default values
-            //    array = ArrayType.$new (dimSizes[0], dimSizes[1], ...)
-            CompValuTemp array = new CompValuTemp (arrayType, this);
-            PushXMRInst ();
-            for (int k = 0; k < rank; k ++) {
-                ilGen.Emit (values, OpCodes.Ldc_I4, dimSizes[k]);
-            }
-            ilGen.Emit (values, OpCodes.Call, newMeth.ilGen);
-            array.Pop (this, arrayType);
-
-            // Figure out where the array's Set() method is
-            TokenType[] setargsig = new TokenType[rank+1];
-            for (int k = 0; k < rank; k ++) {
-                setargsig[k] = tokenTypeInt;
-            }
-            setargsig[rank] = eleType;
-            TokenDeclVar setMeth = FindThisMember (arrayDecl, new TokenName (null, "Set"), setargsig);
-
-            // Fill in the array with the initializer values
-            FillInInitVals (array, setMeth, dimSizes, 0, rank, values, eleType);
-
-            // The array is our resultant value
-            return array;
-        }
-
-        /**
-         * @brief Compute an array's dimensions given its initialization value list
-         * @param dimSizes = filled in with array's dimensions
-         * @param dimNo    = what dimension the 'values' list applies to
-         * @param rank     = total number of dimensions of the array
-         * @param values   = list of values to initialize the array's 'dimNo' dimension with
-         * @returns with dimSizes[dimNo..rank-1] filled in
-         */
-        private static void FillInDimSizes (int[] dimSizes, int dimNo, int rank, TokenList values)
-        {
-            // the size of a dimension is the largest number of initializer elements at this level
-            // for dimNo 0, this is the number of elements in the top-level list
-            if (dimSizes[dimNo] < values.tl.Count) dimSizes[dimNo] = values.tl.Count;
-
-            // see if there is another dimension to calculate
-            if (++ dimNo < rank) {
-
-                // its size is the size of the largest initializer list at the next inner level
-                foreach (Token val in values.tl) {
-                    if (val is TokenList) {
-                        TokenList subvals = (TokenList)val;
-                        FillInDimSizes (dimSizes, dimNo, rank, subvals);
-                    }
-                }
-            }
-        }
-
-        /**
-         * @brief Output code to fill in array's initialization values
-         * @param array      = array to be filled in
-         * @param setMeth    = the array's Set() method
-         * @param subscripts = holds subscripts being built
-         * @param dimNo      = which dimension the 'values' are for
-         * @param values     = list of initialization values for dimension 'dimNo'
-         * @param rank       = number of dimensions of 'array'
-         * @param values     = list of values to initialize the array's 'dimNo' dimension with
-         * @param eleType    = the element's type
-         * @returns with code emitted to initialize array's [subscripts[0], ..., subscripts[dimNo-1], *, *, ...]
-         *                                                          dimNo and up completely filled ---^
-         */
-        private void FillInInitVals (CompValu array, TokenDeclVar setMeth, int[] subscripts, int dimNo, int rank, TokenList values, TokenType eleType)
-        {
-            subscripts[dimNo] = 0;
-            foreach (Token val in values.tl) {
-                CompValu initValue = null;
-
-                /*
-                 * If it is a sublist, process it.
-                 *    If we don't have enough subscripts yet, hopefully that sublist will have enough.
-                 *    If we already have enough subscripts, then that sublist can be for an element of this supposedly jagged array.
-                 */
-                if (val is TokenList) {
-                    TokenList sublist = (TokenList)val;
-                    if (dimNo + 1 < rank) {
-
-                        /*
-                         * We don't have enough subscripts yet, hopefully the sublist has the rest.
-                         */
-                        FillInInitVals (array, setMeth, subscripts, dimNo + 1, rank, sublist, eleType);
-                    } else if ((eleType is TokenTypeSDTypeClass) && (((TokenTypeSDTypeClass)eleType).decl.arrayOfType == null)) {
-
-                        /*
-                         * If we aren't a jagged array either, we can't do anything with the sublist.
-                         */
-                        ErrorMsg (val, "too many brace levels");
-                    } else {
-
-                        /*
-                         * We are a jagged array, so malloc a subarray and initialize it with the sublist.
-                         * Then we can use that subarray to fill this array's element.
-                         */
-                        initValue = MallocAndInitArray (eleType, sublist);
-                    }
-                }
-
-                /*
-                 * If it is a value expression, then output code to compute the value.
-                 */
-                if (val is TokenRVal) {
-                    if (dimNo + 1 < rank) {
-                        ErrorMsg ((Token)val, "not enough brace levels");
-                    } else {
-                        initValue = GenerateFromRVal ((TokenRVal)val);
-                    }
-                }
-
-                /*
-                 * If there is an initValue, output "array.Set (subscript[0], subscript[1], ..., initValue)"
-                 */
-                if (initValue != null) {
-                    array.PushVal (this, val);
-                    for (int i = 0; i <= dimNo; i ++) {
-                        ilGen.Emit (val, OpCodes.Ldc_I4, subscripts[i]);
-                    }
-                    initValue.PushVal (this, val, eleType);
-                    ilGen.Emit (val, OpCodes.Call, setMeth.ilGen);
-                }
-
-                /*
-                 * That subscript is processed one way or another, on to the next.
-                 */
-                subscripts[dimNo] ++;
-            }
-        }
-
-        /**
-         * @brief parenthesized expression
-         * @returns type and location of the result of the computation.
-         */
-        private CompValu GenerateFromRValParen (TokenRValParen rValParen)
-        {
-            return GenerateFromRVal (rValParen.rVal);
-        }
-
-        /**
-         * @brief create a rotation object from the x,y,z,w value expressions.
-         */
-        private CompValu GenerateFromRValRot (TokenRValRot rValRot)
-        {
-            CompValu xRVal, yRVal, zRVal, wRVal;
-
-            xRVal = Trivialize (GenerateFromRVal (rValRot.xRVal), rValRot);
-            yRVal = Trivialize (GenerateFromRVal (rValRot.yRVal), rValRot);
-            zRVal = Trivialize (GenerateFromRVal (rValRot.zRVal), rValRot);
-            wRVal = Trivialize (GenerateFromRVal (rValRot.wRVal), rValRot);
-            return new CompValuRot (new TokenTypeRot (rValRot), xRVal, yRVal, zRVal, wRVal);
-        }
-
-        /**
-         * @brief Using 'this' as a pointer to the current script-defined instance object.
-         *        The value is located in arg #0 of the current instance method.
-         */
-        private CompValu GenerateFromRValThis (TokenRValThis zhis)
-        {
-            if (!IsSDTInstMethod ()) {
-                ErrorMsg (zhis, "cannot access instance member of class from static method");
-                return new CompValuVoid (zhis);
-            }
-            return new CompValuArg (curDeclFunc.sdtClass.MakeRefToken (zhis), 0);
-        }
-
-        /**
-         * @brief 'undefined' constant.
-         *        If this constant gets written to an array element, it will delete that element from the array.
-         *        If the script retrieves an element by key that is not defined, it will get this value.
-         *        This value can be stored in and retrieved from variables of type 'object' or script-defined classes.
-         *        It is a runtime error to cast this value to any other type, eg, 
-         *        we don't allow list or string variables to be null pointers.
-         */
-        private CompValu GenerateFromRValUndef (TokenRValUndef rValUndef)
-        {
-            return new CompValuNull (new TokenTypeUndef (rValUndef));
-        }
-
-        /**
-         * @brief create a vector object from the x,y,z value expressions.
-         */
-        private CompValu GenerateFromRValVec (TokenRValVec rValVec)
-        {
-            CompValu xRVal, yRVal, zRVal;
-
-            xRVal = Trivialize (GenerateFromRVal (rValVec.xRVal), rValVec);
-            yRVal = Trivialize (GenerateFromRVal (rValVec.yRVal), rValVec);
-            zRVal = Trivialize (GenerateFromRVal (rValVec.zRVal), rValVec);
-            return new CompValuVec (new TokenTypeVec (rValVec), xRVal, yRVal, zRVal);
-        }
-
-        /**
-         * @brief Generate code to get the default initialization value for a variable.
-         */
-        private CompValu GenerateFromRValInitDef (TokenRValInitDef rValInitDef)
-        {
-            TokenType type = rValInitDef.type;
-
-            if (type is TokenTypeChar) {
-                return new CompValuChar (type, (char)0);
-            }
-            if (type is TokenTypeRot) {
-                CompValuFloat x = new CompValuFloat (type, ScriptBaseClass.ZERO_ROTATION.x);
-                CompValuFloat y = new CompValuFloat (type, ScriptBaseClass.ZERO_ROTATION.y);
-                CompValuFloat z = new CompValuFloat (type, ScriptBaseClass.ZERO_ROTATION.z);
-                CompValuFloat s = new CompValuFloat (type, ScriptBaseClass.ZERO_ROTATION.s);
-                return new CompValuRot (type, x, y, z, s);
-            }
-            if ((type is TokenTypeKey) || (type is TokenTypeStr)) {
-                return new CompValuString (type, "");
-            }
-            if (type is TokenTypeVec) {
-                CompValuFloat x = new CompValuFloat (type, ScriptBaseClass.ZERO_VECTOR.x);
-                CompValuFloat y = new CompValuFloat (type, ScriptBaseClass.ZERO_VECTOR.y);
-                CompValuFloat z = new CompValuFloat (type, ScriptBaseClass.ZERO_VECTOR.z);
-                return new CompValuVec (type, x, y, z);
-            }
-            if (type is TokenTypeInt) {
-                return new CompValuInteger (type, 0);
-            }
-            if (type is TokenTypeFloat) {
-                return new CompValuFloat (type, 0);
-            }
-            if (type is TokenTypeVoid) {
-                return new CompValuVoid (type);
-            }
-
-            /*
-             * Default for 'object' type is 'undef'.
-             * Likewise for script-defined classes and interfaces.
-             */
-            if ((type is TokenTypeObject) || (type is TokenTypeSDTypeClass) || (type is TokenTypeSDTypeDelegate) || 
-                (type is TokenTypeSDTypeInterface) || (type is TokenTypeExc)) {
-                return new CompValuNull (type);
-            }
-
-            /*
-             * array and list
-             */
-            CompValuTemp temp = new CompValuTemp (type, this);
-            PushDefaultValue (type);
-            temp.Pop (this, rValInitDef, type);
-            return temp;
-        }
-
-        /**
-         * @brief Generate code to process an <rVal> is <type> expression, and produce a boolean value.
-         */
-        private CompValu GenerateFromRValIsType (TokenRValIsType rValIsType)
-        {
-            /*
-             * Expression we want to know the type of.
-             */
-            CompValu val = GenerateFromRVal (rValIsType.rValExp);
-
-            /*
-             * Pass it in to top-level type expression decoder.
-             */
-            return GenerateFromTypeExp (val, rValIsType.typeExp);
-        }
-
-        /**
-         * @brief See if the type of the given value matches the type expression.
-         * @param val = where the value to be evaluated is stored
-         * @param typeExp = script tokens representing type expression
-         * @returns location where the boolean result is stored
-         */
-        private CompValu GenerateFromTypeExp (CompValu val, TokenTypeExp typeExp)
-        {
-            if (typeExp is TokenTypeExpBinOp) {
-                CompValu left  = GenerateFromTypeExp (val, ((TokenTypeExpBinOp)typeExp).leftOp);
-                CompValu right = GenerateFromTypeExp (val, ((TokenTypeExpBinOp)typeExp).rightOp);
-                CompValuTemp result = new CompValuTemp (tokenTypeBool, this);
-                Token op = ((TokenTypeExpBinOp)typeExp).binOp;
-                left.PushVal (this, ((TokenTypeExpBinOp)typeExp).leftOp);
-                right.PushVal (this, ((TokenTypeExpBinOp)typeExp).rightOp);
-                if (op is TokenKwAnd) {
-                    ilGen.Emit (typeExp, OpCodes.And);
-                } else if (op is TokenKwOr) {
-                    ilGen.Emit (typeExp, OpCodes.Or);
-                } else {
-                    throw new Exception ("unknown TokenTypeExpBinOp " + op.GetType ());
-                }
-                result.Pop (this, typeExp);
-                return result;
-            }
-            if (typeExp is TokenTypeExpNot) {
-                CompValu interm = GenerateFromTypeExp (val, ((TokenTypeExpNot)typeExp).typeExp);
-                CompValuTemp result = new CompValuTemp (tokenTypeBool, this);
-                interm.PushVal (this, ((TokenTypeExpNot)typeExp).typeExp, tokenTypeBool);
-                ilGen.Emit (typeExp, OpCodes.Ldc_I4_1);
-                ilGen.Emit (typeExp, OpCodes.Xor);
-                result.Pop (this, typeExp);
-                return result;
-            }
-            if (typeExp is TokenTypeExpPar) {
-                return GenerateFromTypeExp (val, ((TokenTypeExpPar)typeExp).typeExp);
-            }
-            if (typeExp is TokenTypeExpType) {
-                CompValuTemp result = new CompValuTemp (tokenTypeBool, this);
-                val.PushVal (this, typeExp);
-                ilGen.Emit (typeExp, OpCodes.Isinst, ((TokenTypeExpType)typeExp).typeToken.ToSysType ());
-                ilGen.Emit (typeExp, OpCodes.Ldnull);
-                ilGen.Emit (typeExp, OpCodes.Ceq);
-                ilGen.Emit (typeExp, OpCodes.Ldc_I4_1);
-                ilGen.Emit (typeExp, OpCodes.Xor);
-                result.Pop (this, typeExp);
-                return result;
-            }
-            if (typeExp is TokenTypeExpUndef) {
-                CompValuTemp result = new CompValuTemp (tokenTypeBool, this);
-                val.PushVal (this, typeExp);
-                ilGen.Emit (typeExp, OpCodes.Ldnull);
-                ilGen.Emit (typeExp, OpCodes.Ceq);
-                result.Pop (this, typeExp);
-                return result;
-            }
-            throw new Exception ("unknown TokenTypeExp type " + typeExp.GetType ());
-        }
-
-        /**
-         * @brief Push the default (null) value for a particular variable
-         * @param var = variable to get the default value for
-         * @returns with value pushed on stack
-         */
-        public void PushVarDefaultValue (TokenDeclVar var)
-        {
-            PushDefaultValue (var.type);
-        }
-        public void PushDefaultValue (TokenType type)
-        {
-            if (type is TokenTypeArray) {
-                PushXMRInst ();                // instance
-                ilGen.Emit (type, OpCodes.Newobj, xmrArrayConstructorInfo);
-                return;
-            }
-            if (type is TokenTypeChar) {
-                ilGen.Emit (type, OpCodes.Ldc_I4_0);
-                return;
-            }
-            if (type is TokenTypeList) {
-                ilGen.Emit (type, OpCodes.Ldc_I4_0);
-                ilGen.Emit (type, OpCodes.Newarr, typeof (object));
-                ilGen.Emit (type, OpCodes.Newobj, lslListConstructorInfo);
-                return;
-            }
-            if (type is TokenTypeRot) {
-                // Mono is tOO stOOpid to allow: ilGen.Emit (OpCodes.Ldsfld, zeroRotationFieldInfo);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.x);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.y);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.z);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.s);
-                ilGen.Emit (type, OpCodes.Newobj, lslRotationConstructorInfo);
-                return;
-            }
-            if ((type is TokenTypeKey) || (type is TokenTypeStr)) {
-                ilGen.Emit (type, OpCodes.Ldstr, "");
-                return;
-            }
-            if (type is TokenTypeVec) {
-                // Mono is tOO stOOpid to allow: ilGen.Emit (OpCodes.Ldsfld, zeroVectorFieldInfo);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.x);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.y);
-                ilGen.Emit (type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.z);
-                ilGen.Emit (type, OpCodes.Newobj, lslVectorConstructorInfo);
-                return;
-            }
-            if (type is TokenTypeInt) {
-                ilGen.Emit (type, OpCodes.Ldc_I4_0);
-                return;
-            }
-            if (type is TokenTypeFloat) {
-                ilGen.Emit (type, OpCodes.Ldc_R4, 0.0f);
-                return;
-            }
-
-            /*
-             * Default for 'object' type is 'undef'.
-             * Likewise for script-defined classes and interfaces.
-             */
-            if ((type is TokenTypeObject) || (type is TokenTypeSDTypeClass) || (type is TokenTypeSDTypeInterface) || (type is TokenTypeExc)) {
-                ilGen.Emit (type, OpCodes.Ldnull);
-                return;
-            }
-
-            /*
-             * Void is pushed as the default return value of a void function.
-             * So just push nothing as expected of void functions.
-             */
-            if (type is TokenTypeVoid) {
-                return;
-            }
-
-            /*
-             * Default for 'delegate' type is 'undef'.
-             */
-            if (type is TokenTypeSDTypeDelegate) {
-                ilGen.Emit (type, OpCodes.Ldnull);
-                return;
-            }
-
-            throw new Exception ("unknown type " + type.GetType ().ToString ());
-        }
-
-        /**
-         * @brief Determine if the expression has a constant boolean value
-         *        and if so, if the value is true or false.
-         * @param expr = expression to evaluate
-         * @returns true: expression is contant and has boolean value true
-         *         false: otherwise
-         */
-        private bool IsConstBoolExprTrue (CompValu expr)
-        {
-            bool constVal;
-            return IsConstBoolExpr (expr, out constVal) && constVal;
-        }
-
-        private bool IsConstBoolExpr (CompValu expr, out bool constVal)
-        {
-            if (expr is CompValuChar) {
-                constVal = ((CompValuChar)expr).x != 0;
-                return true;
-            }
-            if (expr is CompValuFloat) {
-                constVal = ((CompValuFloat)expr).x != (double)0;
-                return true;
-            }
-            if (expr is CompValuInteger) {
-                constVal = ((CompValuInteger)expr).x != 0;
-                return true;
-            }
-            if (expr is CompValuString) {
-                string s = ((CompValuString)expr).x;
-                constVal = s != "";
-                if (constVal && (expr.type is TokenTypeKey)) {
-                    constVal = s != ScriptBaseClass.NULL_KEY;
-                }
-                return true;
-            }
-
-            constVal = false;
-            return false;
-        }
-
-        /**
-         * @brief Determine if the expression has a constant integer value
-         *        and if so, return the integer value.
-         * @param expr = expression to evaluate
-         * @returns true: expression is contant and has integer value
-         *         false: otherwise
-         */
-        private bool IsConstIntExpr (CompValu expr, out int constVal)
-        {
-            if (expr is CompValuChar) {
-                constVal = (int)((CompValuChar)expr).x;
-                return true;
-            }
-            if (expr is CompValuInteger) {
-                constVal = ((CompValuInteger)expr).x;
-                return true;
-            }
-
-            constVal = 0;
-            return false;
-        }
-
-        /**
-         * @brief Determine if the expression has a constant string value
-         *        and if so, return the string value.
-         * @param expr = expression to evaluate
-         * @returns true: expression is contant and has string value
-         *         false: otherwise
-         */
-        private bool IsConstStrExpr (CompValu expr, out string constVal)
-        {
-            if (expr is CompValuString) {
-                constVal = ((CompValuString)expr).x;
-                return true;
-            }
-            constVal = "";
-            return false;
-        }
-
-        /**
-         * @brief create table of legal event handler prototypes.
-         *        This is used to make sure script's event handler declrations are valid.
-         */
-        private static VarDict CreateLegalEventHandlers ()
-        {
-            /*
-             * Get handler prototypes with full argument lists.
-             */
-            VarDict leh = new InternalFuncDict (typeof (IEventHandlers), false);
-
-            /*
-             * We want the scripts to be able to declare their handlers with
-             * fewer arguments than the full argument lists.  So define additional 
-             * prototypes with fewer arguments.
-             */
-            TokenDeclVar[] fullArgProtos = new TokenDeclVar[leh.Count];
-            int i = 0;
-            foreach (TokenDeclVar fap in leh) fullArgProtos[i++] = fap;
-
-            foreach (TokenDeclVar fap in fullArgProtos) {
-                TokenArgDecl fal = fap.argDecl;
-                int fullArgCount = fal.vars.Length;
-                for (i = 0; i < fullArgCount; i ++) {
-                    TokenArgDecl shortArgList = new TokenArgDecl (null);
-                    for (int j = 0; j < i; j ++) {
-                        TokenDeclVar var = fal.vars[j];
-                        shortArgList.AddArg (var.type, var.name);
-                    }
-                    TokenDeclVar shortArgProto = new TokenDeclVar (null, null, null);
-                    shortArgProto.name         = new TokenName (null, fap.GetSimpleName ());
-                    shortArgProto.retType      = fap.retType;
-                    shortArgProto.argDecl      = shortArgList;
-                    leh.AddEntry (shortArgProto);
-                }
-            }
-
-            return leh;
-        }
-
-        /**
-         * @brief Emit a call to CheckRun(), (voluntary multitasking switch)
-         */
-        public void EmitCallCheckRun (Token errorAt, bool stack)
-        {
-            if (curDeclFunc.IsFuncTrivial (this)) throw new Exception (curDeclFunc.fullName + " is supposed to be trivial");
-            new CallLabel (this, errorAt);                               // jump here when stack restored
-            PushXMRInst ();                                              // instance
-            ilGen.Emit (errorAt, OpCodes.Call, stack ? checkRunStackMethInfo : checkRunQuickMethInfo);
-            openCallLabel = null;
-        }
-
-        /**
-         * @brief Emit code to push a callNo var on the stack.
-         */
-        public void GetCallNo (Token errorAt, ScriptMyLocal callNoVar)
-        {
-            ilGen.Emit (errorAt, OpCodes.Ldloc, callNoVar);
-            //ilGen.Emit (errorAt, OpCodes.Ldloca, callNoVar);
-            //ilGen.Emit (errorAt, OpCodes.Volatile);
-            //ilGen.Emit (errorAt, OpCodes.Ldind_I4);
-        }
-        public void GetCallNo (Token errorAt, CompValu callNoVar)
-        {
-            callNoVar.PushVal (this, errorAt);
-            //callNoVar.PushRef (this, errorAt);
-            //ilGen.Emit (errorAt, OpCodes.Volatile);
-            //ilGen.Emit (errorAt, OpCodes.Ldind_I4);
-        }
-
-        /**
-         * @brief Emit code to set a callNo var to a given constant.
-         */
-        public void SetCallNo (Token errorAt, ScriptMyLocal callNoVar, int val)
-        {
-            ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
-            ilGen.Emit (errorAt, OpCodes.Stloc, callNoVar);
-            //ilGen.Emit (errorAt, OpCodes.Ldloca, callNoVar);
-            //ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
-            //ilGen.Emit (errorAt, OpCodes.Volatile);
-            //ilGen.Emit (errorAt, OpCodes.Stind_I4);
-        }
-        public void SetCallNo (Token errorAt, CompValu callNoVar, int val)
-        {
-            callNoVar.PopPre (this, errorAt);
-            ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
-            callNoVar.PopPost (this, errorAt);
-            //callNoVar.PushRef (this, errorAt);
-            //ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
-            //ilGen.Emit (errorAt, OpCodes.Volatile);
-            //ilGen.Emit (errorAt, OpCodes.Stind_I4);
-        }
-
-        /**
-         * @brief handle a unary operator, such as -x.
-         */
-        private CompValu UnOpGenerate (CompValu inRVal, Token opcode)
-        {
-            /*
-             * - Negate
-             */
-            if (opcode is TokenKwSub) {
-                if (inRVal.type is TokenTypeFloat) {
-                    CompValuTemp outRVal = new CompValuTemp (new TokenTypeFloat (opcode), this);
-                    inRVal.PushVal (this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
-                    ilGen.Emit (opcode, OpCodes.Neg);     // compute the negative
-                    outRVal.Pop (this, opcode);           // pop into result
-                    return outRVal;                       // tell caller where we put it
-                }
-                if (inRVal.type is TokenTypeInt) {
-                    CompValuTemp outRVal = new CompValuTemp (new TokenTypeInt (opcode), this);
-                    inRVal.PushVal (this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
-                    ilGen.Emit (opcode, OpCodes.Neg);     // compute the negative
-                    outRVal.Pop (this, opcode);           // pop into result
-                    return outRVal;                       // tell caller where we put it
-                }
-                if (inRVal.type is TokenTypeRot) {
-                    CompValuTemp outRVal = new CompValuTemp (inRVal.type, this);
-                    inRVal.PushVal (this, opcode);        // push rotation, then call negate routine
-                    ilGen.Emit (opcode, OpCodes.Call, lslRotationNegateMethodInfo);
-                    outRVal.Pop (this, opcode);           // pop into result
-                    return outRVal;                       // tell caller where we put it
-                }
-                if (inRVal.type is TokenTypeVec) {
-                    CompValuTemp outRVal = new CompValuTemp (inRVal.type, this);
-                    inRVal.PushVal (this, opcode);        // push vector, then call negate routine
-                    ilGen.Emit (opcode, OpCodes.Call, lslVectorNegateMethodInfo);
-                    outRVal.Pop (this, opcode);           // pop into result
-                    return outRVal;                       // tell caller where we put it
-                }
-                ErrorMsg (opcode, "can't negate a " + inRVal.type.ToString ());
-                return inRVal;
-            }
-
-            /*
-             * ~ Complement (bitwise integer)
-             */
-            if (opcode is TokenKwTilde) {
-                if (inRVal.type is TokenTypeInt) {
-                    CompValuTemp outRVal = new CompValuTemp (new TokenTypeInt (opcode), this);
-                    inRVal.PushVal (this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
-                    ilGen.Emit (opcode, OpCodes.Not);     // compute the complement
-                    outRVal.Pop (this, opcode);           // pop into result
-                    return outRVal;                       // tell caller where we put it
-                }
-                ErrorMsg (opcode, "can't complement a " + inRVal.type.ToString ());
-                return inRVal;
-            }
-
-            /*
-             * ! Not (boolean)
-             *
-             * We stuff the 0/1 result in an int because I've seen x+!y in scripts
-             * and we don't want to have to create tables to handle int+bool and
-             * everything like that.
-             */
-            if (opcode is TokenKwExclam) {
-                CompValuTemp outRVal = new CompValuTemp (new TokenTypeInt (opcode), this);
-                inRVal.PushVal (this, opcode, tokenTypeBool);  // anything converts to boolean
-                ilGen.Emit (opcode, OpCodes.Ldc_I4_1);         // then XOR with 1 to flip it
-                ilGen.Emit (opcode, OpCodes.Xor);
-                outRVal.Pop (this, opcode);                    // pop into result
-                return outRVal;                                // tell caller where we put it
-            }
-
-            throw new Exception ("unhandled opcode " + opcode.ToString ());
-        }
-
-        /**
-         * @brief This is called while trying to compute the value of constant initializers.
-         *        It is passed a name and that name is looked up in the constant tables.
-         */
-        private TokenRVal LookupInitConstants (TokenRVal rVal, ref bool didOne)
-        {
-            /*
-             * If it is a static field of a script-defined type, look it up and hopefully we find a constant there.
-             */
-            TokenDeclVar gblVar;
-            if (rVal is TokenLValSField) {
-                TokenLValSField lvsf = (TokenLValSField)rVal;
-                if (lvsf.baseType is TokenTypeSDTypeClass) {
-                    TokenDeclSDTypeClass sdtClass = ((TokenTypeSDTypeClass)lvsf.baseType).decl;
-                    gblVar = sdtClass.members.FindExact (lvsf.fieldName.val, null);
-                    if (gblVar != null) {
-                        if (gblVar.constant && (gblVar.init is TokenRValConst)) {
-                            didOne = true;
-                            return gblVar.init;
-                        }
-                    }
-                }
-                return rVal;
-            }
-
-            /*
-             * Only other thing we handle is stand-alone names.
-             */
-            if (!(rVal is TokenLValName)) return rVal;
-            string name = ((TokenLValName)rVal).name.val;
-
-            /*
-             * If we are doing the initializations for a script-defined type,
-             * look for the constant among the fields for that type.
-             */
-            if (currentSDTClass != null) {
-                gblVar = currentSDTClass.members.FindExact (name, null);
-                if (gblVar != null) {
-                    if (gblVar.constant && (gblVar.init is TokenRValConst)) {
-                        didOne = true;
-                        return gblVar.init;
-                    }
-                    return rVal;
-                }
-            }
-
-            /*
-             * Look it up as a script-defined global variable.
-             * Then if the variable is defined as a constant and has a constant value,
-             * we are successful.  If it is defined as something else, return failure.
-             */
-            gblVar = tokenScript.variablesStack.FindExact (name, null);
-            if (gblVar != null) {
-                if (gblVar.constant && (gblVar.init is TokenRValConst)) {
-                    didOne = true;
-                    return gblVar.init;
-                }
-                return rVal;
-            }
-
-            /*
-             * Maybe it is a built-in symbolic constant.
-             */
-            ScriptConst scriptConst = ScriptConst.Lookup (name);
-            if (scriptConst != null) {
-                rVal = CompValuConst2RValConst (scriptConst.rVal, rVal);
-                if (rVal is TokenRValConst) {
-                    didOne = true;
-                    return rVal;
-                }
-            }
-
-            /*
-             * Don't know what it is, return failure.
-             */
-            return rVal;
-        }
-
-        /**
-         * @brief This is called while trying to compute the value of constant expressions.
-         *        It is passed a name and that name is looked up in the constant tables.
-         */
-        private TokenRVal LookupBodyConstants (TokenRVal rVal, ref bool didOne)
-        {
-            /*
-             * If it is a static field of a script-defined type, look it up and hopefully we find a constant there.
-             */
-            TokenDeclVar gblVar;
-            if (rVal is TokenLValSField) {
-                TokenLValSField lvsf = (TokenLValSField)rVal;
-                if (lvsf.baseType is TokenTypeSDTypeClass) {
-                    TokenDeclSDTypeClass sdtClass = ((TokenTypeSDTypeClass)lvsf.baseType).decl;
-                    gblVar = sdtClass.members.FindExact (lvsf.fieldName.val, null);
-                    if ((gblVar != null) && gblVar.constant && (gblVar.init is TokenRValConst)) {
-                        didOne = true;
-                        return gblVar.init;
-                    }
-                }
-                return rVal;
-            }
-
-            /*
-             * Only other thing we handle is stand-alone names.
-             */
-            if (!(rVal is TokenLValName)) return rVal;
-            string name = ((TokenLValName)rVal).name.val;
-
-            /*
-             * Scan through the variable stack and hopefully we find a constant there.
-             * But we stop as soon as we get a match because that's what the script is referring to.
-             */
-            CompValu val;
-            for (VarDict vars = ((TokenLValName)rVal).stack; vars != null; vars = vars.outerVarDict) {
-                TokenDeclVar var = vars.FindExact (name, null);
-                if (var != null) {
-                    val = var.location;
-                    goto foundit;
-                }
-
-                TokenDeclSDTypeClass baseClass = vars.thisClass;
-                if (baseClass != null) {
-                    while ((baseClass = baseClass.extends) != null) {
-                        var = baseClass.members.FindExact (name, null);
-                        if (var != null) {
-                            val = var.location;
-                            goto foundit;
-                        }
-                    }
-                }
-            }
-
-            /*
-             * Maybe it is a built-in symbolic constant.
-             */
-            ScriptConst scriptConst = ScriptConst.Lookup (name);
-            if (scriptConst != null) {
-                val = scriptConst.rVal;
-                goto foundit;
-            }
-
-            /*
-             * Don't know what it is, return failure.
-             */
-            return rVal;
-
-            /*
-             * Found a CompValu.  If it's a simple constant, then use it.
-             * Otherwise tell caller we failed to simplify.
-             */
-        foundit:
-            rVal = CompValuConst2RValConst (val, rVal);
-            if (rVal is TokenRValConst) {
-                didOne = true;
-            }
-            return rVal;
-        }
-
-        private static TokenRVal CompValuConst2RValConst (CompValu val, TokenRVal rVal)
-        {
-            if (val is CompValuChar)    rVal = new TokenRValConst (rVal, ((CompValuChar)val).x);
-            if (val is CompValuFloat)   rVal = new TokenRValConst (rVal, ((CompValuFloat)val).x);
-            if (val is CompValuInteger) rVal = new TokenRValConst (rVal, ((CompValuInteger)val).x);
-            if (val is CompValuString)  rVal = new TokenRValConst (rVal, ((CompValuString)val).x);
-            return rVal;
-        }
-
-        /**
-         * @brief Generate code to push XMRInstanceSuperType pointer on stack.
-         */
-        public void PushXMRInst ()
-        {
-            if (instancePointer == null) {
-                ilGen.Emit (null, OpCodes.Ldarg_0);
-            } else {
-                ilGen.Emit (null, OpCodes.Ldloc, instancePointer);
-            }
-        }
-
-        /**
-         * @returns true: Ldarg_0 gives XMRSDTypeClObj pointer
-         *                - this is the case for instance methods
-         *         false: Ldarg_0 gives XMR_Instance pointer
-         *                - this is the case for both global functions and static methods
-         */
-        public bool IsSDTInstMethod ()
-        {
-            return (curDeclFunc.sdtClass != null) && 
-                   ((curDeclFunc.sdtFlags & ScriptReduce.SDT_STATIC) == 0);
-        }
-
-        /**
-         * @brief Look for a simply named function or variable (not a field or method)
-         */
-        public TokenDeclVar FindNamedVar (TokenLValName lValName, TokenType[] argsig)
-        {
-            /*
-             * Look in variable stack for the given name.
-             */
-            for (VarDict vars = lValName.stack; vars != null; vars = vars.outerVarDict) {
-
-                // first look for it possibly with an argument signature
-                // so we pick the correct overloaded method
-                TokenDeclVar var = FindSingleMember (vars, lValName.name, argsig);
-                if (var != null) return var;
-
-                // if that fails, try it without the argument signature.
-                // delegates get entered like any other variable, ie, 
-                // no signature on their name.
-                if (argsig != null) {
-                    var = FindSingleMember (vars, lValName.name, null);
-                    if (var != null) return var;
-                }
-
-                // if this is the frame for some class members, try searching base class members too
-                TokenDeclSDTypeClass baseClass = vars.thisClass;
-                if (baseClass != null) {
-                    while ((baseClass = baseClass.extends) != null) {
-                        var = FindSingleMember (baseClass.members, lValName.name, argsig);
-                        if (var != null) return var;
-                        if (argsig != null) {
-                            var = FindSingleMember (baseClass.members, lValName.name, null);
-                            if (var != null) return var;
-                        }
-                    }
-                }
-            }
-
-            /*
-             * If not found, try one of the built-in constants or functions.
-             */
-            if (argsig == null) {
-                ScriptConst scriptConst = ScriptConst.Lookup (lValName.name.val);
-                if (scriptConst != null) {
-                    TokenDeclVar var = new TokenDeclVar (lValName.name, null, tokenScript);
-                    var.name     = lValName.name;
-                    var.type     = scriptConst.rVal.type;
-                    var.location = scriptConst.rVal;
-                    return var;
-                }
-            } else {
-                TokenDeclVar inline = FindSingleMember (TokenDeclInline.inlineFunctions, lValName.name, argsig);
-                if (inline != null) return inline;
-            }
-
-            return null;
-        }
-
-
-        /**
-         * @brief Find a member of an interface.
-         * @param sdType = interface type
-         * @param name = name of member to find
-         * @param argsig = null: field/property; else: script-visible method argument types
-         * @param baseRVal = pointer to interface object
-         * @returns null: no such member
-         *          else: pointer to member
-         *                baseRVal = possibly modified to point to type-casted interface object
-         */
-        private TokenDeclVar FindInterfaceMember (TokenTypeSDTypeInterface sdtType, TokenName name, TokenType[] argsig, ref CompValu baseRVal)
-        {
-            TokenDeclSDTypeInterface sdtDecl = sdtType.decl;
-            TokenDeclSDTypeInterface impl;
-            TokenDeclVar declVar = sdtDecl.FindIFaceMember (this, name, argsig, out impl);
-            if ((declVar != null) && (impl != sdtDecl)) {
-
-                /*
-                 * Accessing a method or propterty of another interface that the primary interface says it implements.
-                 * In this case, we have to cast from the primary interface to that secondary interface.
-                 *
-                 * interface IEnumerable {
-                 *     IEnumerator GetEnumerator ();
-                 * }
-                 * interface ICountable : IEnumerable {
-                 *     integer GetCount ();
-                 * }
-                 * class List : ICountable {
-                 *     public GetCount () : ICountable { ... }
-                 *     public GetEnumerator () : IEnumerable { ... }
-                 * }
-                 *
-                 *     ICountable aList = new List ();
-                 *     IEnumerator anEnumer = aList.GetEnumerator ();   << we are here
-                 *                                                      << baseRVal = aList
-                 *                                                      << sdtDecl = ICountable
-                 *                                                      << impl = IEnumerable
-                 *                                                      << name = GetEnumerator
-                 *                                                      << argsig = ()
-                 * So we have to cast aList from ICountable to IEnumerable.
-                 */
-
-                // make type token for the secondary interface type
-                TokenType subIntfType = impl.MakeRefToken (name);
-
-                // make a temp variable of the secondary interface type
-                CompValuTemp castBase = new CompValuTemp (subIntfType, this);
-
-                // output code to cast from the primary interface to the secondary interface
-                // this is 2 basic steps:
-                // 1) cast from primary interface object -> class object
-                //    ...gets it from interfaceObject.delegateArray[0].Target
-                // 2) cast from class object -> secondary interface object
-                //    ...gets it from classObject.sdtcITable[interfaceIndex]
-                baseRVal.PushVal (this, name, subIntfType);
-
-                // save result of casting in temp
-                castBase.Pop (this, name);
-
-                // return temp reference
-                baseRVal = castBase;
-            }
-
-            return declVar;
-        }
-
-        /**
-         * @brief Find a member of a script-defined type class.
-         * @param sdtType = reference to class declaration
-         * @param name = name of member to find
-         * @param argsig = argument signature used to select among overloaded members
-         * @returns null: no such member found
-         *          else: the member found
-         */
-        public TokenDeclVar FindThisMember (TokenTypeSDTypeClass sdtType, TokenName name, TokenType[] argsig)
-        {
-            return FindThisMember (sdtType.decl, name, argsig);
-        }
-        public TokenDeclVar FindThisMember (TokenDeclSDTypeClass sdtDecl, TokenName name, TokenType[] argsig)
-        {
-            for (TokenDeclSDTypeClass sdtd = sdtDecl; sdtd != null; sdtd = sdtd.extends) {
-                TokenDeclVar declVar = FindSingleMember (sdtd.members, name, argsig);
-                if (declVar != null) return declVar;
-            }
-            return null;
-        }
-
-        /**
-         * @brief Look for a single member that matches the given name and argument signature
-         * @param where = which dictionary to look in
-         * @param name = basic name of the field or method, eg, "Printable"
-         * @param argsig = argument types the method is being called with, eg, "(string)"
-         *                 or null to find a field
-         * @returns null: no member found
-         *          else: the member found
-         */
-        public TokenDeclVar FindSingleMember (VarDict where, TokenName name, TokenType[] argsig)
-        {
-            TokenDeclVar[] members = where.FindCallables (name.val, argsig);
-            if (members == null) return null;
-            if (members.Length > 1) {
-                ErrorMsg (name, "more than one matching member");
-                for (int i = 0; i < members.Length; i ++) {
-                    ErrorMsg (members[i], "  " + members[i].argDecl.GetArgSig ());
-                }
-            }
-            return members[0];
-        }
-
-        /**
-         * @brief Find an exact function name and argument signature match.
-         *        Also verify that the return value type is an exact match.
-         * @param where = which method dictionary to look in
-         * @param name = basic name of the method, eg, "Printable"
-         * @param ret = expected return value type
-         * @param argsig = argument types the method is being called with, eg, "(string)"
-         * @returns null: no exact match found
-         *          else: the matching function
-         */
-        private TokenDeclVar FindExactWithRet (VarDict where, TokenName name, TokenType ret, TokenType[] argsig)
-        {
-            TokenDeclVar func = where.FindExact (name.val, argsig);
-            if ((func != null) && (func.retType.ToString () != ret.ToString ())) {
-                ErrorMsg (name, "return type mismatch, have " + func.retType.ToString () + ", expect " + ret.ToString ());
-            }
-            if (func != null) CheckAccess (func, name);
-            return func;
-        }
-
-        /**
-         * @brief Check the private/protected/public access flags of a member.
-         */
-        private void CheckAccess (TokenDeclVar var, Token errorAt)
-        {
-            TokenDeclSDType nested;
-            TokenDeclSDType definedBy  = var.sdtClass;
-            TokenDeclSDType accessedBy = curDeclFunc.sdtClass;
-
-            /*******************************\
-             *  Check member-level access  *
-            \*******************************/
-
-            /*
-             * Note that if accessedBy is null, ie, accessing from global function (or event handlers),
-             * anything tagged as SDT_PRIVATE or SDT_PROTECTED will fail.
-             */
-
-            /*
-             * Private means accessed by the class that defined the member or accessed by a nested class
-             * of the class that defined the member.
-             */
-            if ((var.sdtFlags & ScriptReduce.SDT_PRIVATE) != 0) {
-                for (nested = accessedBy; nested != null; nested = nested.outerSDType) {
-                    if (nested == definedBy) goto acc1ok;
-                }
-                ErrorMsg (errorAt, "private member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName);
-                return;
-            }
-
-            /*
-             * Protected means:
-             *   If being accessed by an inner class, the inner class has access to it if the inner class derives 
-             *   from the declaring class.  It also has access to it if an outer class derives from the declaring 
-             *   class.
-             */
-            if ((var.sdtFlags & ScriptReduce.SDT_PROTECTED) != 0) {
-                for (nested = accessedBy; nested != null; nested = nested.outerSDType) {
-                    for (TokenDeclSDType rootward = nested; rootward != null; rootward = rootward.extends) {
-                        if (rootward == definedBy) goto acc1ok;
-                    }
-                }
-                ErrorMsg (errorAt, "protected member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName);
-                return;
-            }
-        acc1ok:
-
-            /******************************\
-             *  Check class-level access  *
-            \******************************/
-
-            /*
-             * If being accessed by same or inner class than where defined, it is ok.
-             *
-             *      class DefiningClass {
-             *          varBeingAccessed;
-             *                         .
-             *                         .
-             *                         .
-             *                  class AccessingClass {
-             *                      functionDoingAccess() { }
-             *                  }
-             *                         .
-             *                         .
-             *                         .
-             *      }
-             */
-            nested = accessedBy;
-            while (true) {
-                if (nested == definedBy) return;
-                if (nested == null) break;
-                nested = (TokenDeclSDTypeClass)nested.outerSDType;
-            }
-
-            /*
-             * It is being accessed by an outer class than where defined, 
-             * check for a 'private' or 'protected' class tag that blocks.
-             */
-            do {
-
-                /*
-                 * If the field's class is defined directly inside the accessing class,
-                 * access is allowed regardless of class-level private or protected tags.
-                 *
-                 *      class AccessingClass {
-                 *          functionDoingAccess() { }
-                 *          class DefiningClass {
-                 *              varBeingAccessed;
-                 *          }
-                 *      }
-                 */
-                if (definedBy.outerSDType == accessedBy) return;
-
-                /*
-                 * If the field's class is defined two or more levels inside the accessing class, 
-                 * access is denied if the defining class is tagged private.
-                 *
-                 *      class AccessingClass {
-                 *          functionDoingAccess() { }
-                 *                         .
-                 *                         .
-                 *                         .
-                 *                  class IntermediateClass {
-                 *                      private class DefiningClass {
-                 *                          varBeingAccessed;
-                 *                      }
-                 *                  }
-                 *                         .
-                 *                         .
-                 *                         .
-                 *      }
-                 */
-                if ((definedBy.accessLevel & ScriptReduce.SDT_PRIVATE) != 0) {
-                    ErrorMsg (errorAt, "member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName + 
-                                       " because of private class " + definedBy.longName.val);
-                    return;
-                }
-
-                /*
-                 * Likewise, if DefiningClass is tagged protected, the AccessingClass must derive from the
-                 * IntermediateClass or access is denied.
-                 */
-                if ((definedBy.accessLevel & ScriptReduce.SDT_PROTECTED) != 0) {
-                    for (TokenDeclSDType extends = accessedBy; extends != definedBy.outerSDType; extends = extends.extends) {
-                        if (extends == null) {
-                            ErrorMsg (errorAt, "member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName + 
-                                               " because of protected class " + definedBy.longName.val);
-                            return;
-                        }
-                    }
-                }
-
-                /*
-                 * Check next outer level.
-                 */
-                definedBy = definedBy.outerSDType;
-            } while (definedBy != null);
-        }
-
-        /**
-         * @brief Convert a list of argument types to printable string, eg, "(list,string,float,integer)"
-         *        If given a null, return "" indicating it is a field not a method
-         */
-        public static string ArgSigString (TokenType[] argsig)
-        {
-            if (argsig == null) return "";
-            StringBuilder sb = new StringBuilder ("(");
-            for (int i = 0; i < argsig.Length; i ++) {
-                if (i > 0) sb.Append (",");
-                sb.Append (argsig[i].ToString ());
-            }
-            sb.Append (")");
-            return sb.ToString ();
-        }
-
-        /**
-         * @brief output error message and remember that we did
-         */
-        public void ErrorMsg (Token token, string message)
-        {
-            if ((token == null) || (token.emsg == null)) token = errorMessageToken;
-            if (!youveAnError || (token.file != lastErrorFile) || (token.line > lastErrorLine)) {
-                token.ErrorMsg (message);
-                youveAnError  = true;
-                lastErrorFile = token.file;
-                lastErrorLine = token.line;
-            }
-        }
-
-        /**
-         * @brief Find a private static method.
-         * @param owner = class the method is part of
-         * @param name = name of method to find
-         * @param args = array of argument types
-         * @returns pointer to method
-         */
-        public static MethodInfo GetStaticMethod (Type owner, string name, Type[] args)
-        {
-            MethodInfo mi = owner.GetMethod (name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
-            if (mi == null) {
-                throw new Exception ("undefined method " + owner.ToString () + "." + name);
-            }
-            return mi;
-        }
-
-        // http://wiki.secondlife.com/wiki/Rotation 'negate a rotation' says just negate .s component
-        // but http://wiki.secondlife.com/wiki/LSL_Language_Test (lslangtest1.lsl) says negate all 4 values
-        public static LSL_Rotation LSLRotationNegate (LSL_Rotation r) { return new LSL_Rotation (-r.x,-r.y,-r.z,-r.s); }
-        public static LSL_Vector   LSLVectorNegate   (LSL_Vector v)   { return -v; }
-        public static string       CatchExcToStr     (Exception exc)  { return exc.ToString(); }
-        //public static void       ConsoleWrite      (string str)     { Console.Write(str); }
-
-        /**
-         * @brief Defines an internal label that is used as a target for 'break' and 'continue' statements.
-         */
-        private class BreakContTarg {
-            public bool used;
-            public ScriptMyLabel label;
-            public TokenStmtBlock block;
-
-            public BreakContTarg (ScriptCodeGen scg, string name) {
-                used  = false;                         // assume it isn't referenced at all
-                label = scg.ilGen.DefineLabel (name);  // label that the break/continue jumps to
-                block = scg.curStmtBlock;              // { ... } that the break/continue label is in
-            }
-        }
-    }
-
-    /**
-     * @brief Marker interface indicates an exception that can't be caught by a script-level try/catch.
-     */
-    public interface IXMRUncatchable { }
-
-    /**
-     * @brief Thrown by a script when it attempts to change to an undefined state.
-     * These can be detected at compile time but the moron XEngine compiles
-     * such things, so we compile them as runtime errors.
-     */
-    [SerializableAttribute]
-    public class ScriptUndefinedStateException : Exception, ISerializable {
-        public string stateName;
-        public ScriptUndefinedStateException (string stateName) : base ("undefined state " + stateName) {
-            this.stateName = stateName;
-        }
-        protected ScriptUndefinedStateException (SerializationInfo info, StreamingContext context) : base (info, context)
-        { }
-    }
-
-    /**
-     * @brief Created by a throw statement.
-     */
-    [SerializableAttribute]
-    public class ScriptThrownException : Exception, ISerializable {
-        public object thrown;
-
-        /**
-         * @brief Called by a throw statement to wrap the object in a unique
-         *        tag that capable of capturing a stack trace.  Script can 
-         *        unwrap it by calling xmrExceptionThrownValue().
-         */
-        public static Exception Wrap (object thrown)
-        {
-            return new ScriptThrownException (thrown);
-        }
-        private ScriptThrownException (object thrown) : base (thrown.ToString ())
-        {
-            this.thrown = thrown;
-        }
-
-        /**
-         * @brief Used by serialization/deserialization.
-         */
-        protected ScriptThrownException (SerializationInfo info, StreamingContext context) : base (info, context)
-        { }
-    }
-
-    /**
-     * @brief Thrown by a script when it attempts to change to a defined state.
-     */
-    [SerializableAttribute]
-    public class ScriptChangeStateException : Exception, ISerializable, IXMRUncatchable {
-        public int newState;
-        public ScriptChangeStateException (int newState) {
-            this.newState = newState;
-        }
-        protected ScriptChangeStateException (SerializationInfo info, StreamingContext context) : base (info, context)
-        { }
-    }
-
-    /**
-     * @brief We are restoring to the body of a catch { } so we need to 
-     *        wrap the original exception in an outer exception, so the 
-     *        system won't try to refill the stack trace.
-     *
-     *        We don't mark this one serializable as it should never get 
-     *        serialized out.  It only lives from the throw to the very 
-     *        beginning of the catch handler where it is promptly unwrapped.
-     *        No CheckRun() call can possibly intervene.
-     */
-    public class ScriptRestoreCatchException : Exception {
-
-        // old code uses these
-        private object e;
-        public ScriptRestoreCatchException (object e) {
-            this.e = e;
-        }
-        public static object Unwrap (object o)
-        {
-            if (o is IXMRUncatchable) return null;
-            if (o is ScriptRestoreCatchException) return ((ScriptRestoreCatchException)o).e;
-            return o;
-        }
-
-        // new code uses these
-        private Exception ee;
-        public ScriptRestoreCatchException (Exception ee) {
-            this.ee = ee;
-        }
-        public static Exception Unwrap (Exception oo)
-        {
-            if (oo is IXMRUncatchable) return null;
-            if (oo is ScriptRestoreCatchException) return ((ScriptRestoreCatchException)oo).ee;
-            return oo;
-        }
-    }
-
-    [SerializableAttribute]
-    public class ScriptBadCallNoException : Exception {
-        public ScriptBadCallNoException (int callNo) : base ("bad callNo " + callNo) { }
-        protected ScriptBadCallNoException (SerializationInfo info, StreamingContext context) : base (info, context)
-        { }
-    }
-
-    public class CVVMismatchException : Exception {
-        public int oldcvv;
-        public int newcvv;
-
-        public CVVMismatchException (int oldcvv, int newcvv) : base ("object version is " + oldcvv.ToString () + 
-                                                             " but accept only " + newcvv.ToString ())
-        {
-            this.oldcvv = oldcvv;
-            this.newcvv = newcvv;
-        }
-    }
-}

+ 0 - 2637
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCollector.cs

@@ -1,2637 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-
-
-/**
- * @brief Wrapper class for ScriptMyILGen to do simple optimizations.
- *        The main one is to figure out which locals are active at the labels
- *        so the stack capture/restore code doesn't have to do everything.
- *        Second is it removes unnecessary back-to-back stloc/ldloc's.
- */
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    /**
-     * @brief This is a list that keeps track of types pushed on the evaluation stack.
-     */
-    public class StackDepth : List<Type> {
-        public List<bool> isBoxeds = new List<bool> ();
-
-        /**
-         * @brief Clear both stacks.
-         */
-        public new void Clear ()
-        {
-            base.Clear ();
-            isBoxeds.Clear ();
-        }
-
-        /**
-         * @brief Pop call parameters and validate the types.
-         */
-        public void Pop (ParameterInfo[] pis)
-        {
-            int n = pis.Length;
-            int c = this.Count;
-            if (n > c) throw new Exception ("stack going negative");
-            for (int i = n; -- i >= 0;) {
-                -- c;
-                ExpectedVsOnStack (pis[i].ParameterType, this[c], isBoxeds[c]);
-            }
-            Pop (n);
-        }
-
-        /**
-         * @brief Pop values and validate the types.
-         */
-        public void Pop (Type[] ts)
-        {
-            int n = ts.Length;
-            int c = this.Count;
-            if (n > c) throw new Exception ("stack going negative");
-            for (int i = ts.Length; -- i >= 0;) {
-                -- c;
-                ExpectedVsOnStack (ts[i], this[c], isBoxeds[c]);
-            }
-            Pop (n);
-        }
-
-        /**
-         * @brief Pop a single value and validate the type.
-         */
-        public void Pop (Type t)
-        {
-            int c = this.Count;
-            if (c < 1) throw new Exception ("stack going negative");
-            ExpectedVsOnStack (t, this[c-1], isBoxeds[c-1]);
-            Pop (1);
-        }
-
-        /**
-         * @brief Pop a single value and validate that it is a numeric type.
-         */
-        public Type PopNumVal ()
-        {
-            int c = this.Count;
-            if (c < 1) throw new Exception ("stack going negative");
-            Type st = this[--c];
-            if (st == null) {
-                throw new Exception ("stack has null, expecting a numeric");
-            }
-            if (isBoxeds[c]) {
-                throw new Exception ("stack is boxed " + st.Name + ", expecting a numeric");
-            }
-            if ((st != typeof (bool)) && (st != typeof (char))  && (st != typeof (int)) && 
-                (st != typeof (long)) && (st != typeof (float)) && (st != typeof (double))) {
-                throw new Exception ("stack has " + st.Name + ", expecting a numeric");
-            }
-            return Pop (1);
-        }
-
-        /**
-         * @brief Pop a single value and validate that it is a reference type
-         */
-        public Type PopRef ()
-        {
-            int c = this.Count;
-            if (c < 1) throw new Exception ("stack going negative");
-            Type st = this[--c];
-            if ((st != null) && !isBoxeds[c] && st.IsValueType) {
-                throw new Exception ("stack has " + st.Name + ", expecting a ref type");
-            }
-            return Pop (1);
-        }
-
-        /**
-         * @brief Pop a single value and validate that it is a value type
-         */
-        public Type PopValue ()
-        {
-            int c = this.Count;
-            if (c < 1) throw new Exception ("stack going negative");
-            Type st = this[--c];
-            if (st == null) {
-                throw new Exception ("stack has null, expecting a value type");
-            }
-            if (!st.IsValueType) {
-                throw new Exception ("stack has " + st.Name + ", expecting a value type");
-            }
-            if (isBoxeds[c]) {
-                throw new Exception ("stack has boxed " + st.Name + ", expecting an unboxed value type");
-            }
-            return Pop (1);
-        }
-
-        // ex = what is expected to be on stack
-        // st = what is actually on stack (null for ldnull)
-        // stBoxed = stack value is boxed
-        public static void ExpectedVsOnStack (Type ex, Type st, bool stBoxed)
-        {
-            // ldnull pushed on stack can go into any pointer type
-            if (st == null) {
-                if (ex.IsByRef || ex.IsPointer || ex.IsClass || ex.IsInterface) return;
-                throw new Exception ("stack has null, expect " + ex.Name);
-            }
-
-            // simple case of expecting an object
-            // ...so the stack can have object,string, etc
-            // but we cant allow int = boxed int here
-            if (ex.IsAssignableFrom (st) && !stBoxed) return;
-
-            // case of expecting an enum on the stack
-            // but all the CIL code knows about are ints etc
-            // so convert the Enum type to integer or whatever
-            // and that should be assignable from what's on stack
-            if (ex.IsEnum && typeof (int).IsAssignableFrom (st)) return;
-
-            // bool, char, int are interchangeable on the stack
-            if ((ex == typeof (bool) || ex == typeof (char) || ex == typeof (int)) && 
-                (st == typeof (bool) || st == typeof (char) || st == typeof (int))) return;
-
-            // float and double are interchangeable on the stack
-            if ((ex == typeof (float) || ex == typeof (double)) && 
-                (st == typeof (float) || st == typeof (double))) return;
-
-            // object can accept any boxed type
-            if ((ex == typeof (object)) && stBoxed) return;
-
-            // otherwise, it is disallowed
-            throw new Exception ("stack has " + StackTypeString (st, stBoxed) + ", expect " + ex.Name);
-        }
-
-        /**
-         * @brief Pop values without any validation.
-         */
-        public Type Pop (int n)
-        {
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-            Type lastPopped = null;
-            int c = this.Count;
-            if (n > c) throw new Exception ("stack going negative");
-            if (n > 0) {
-                lastPopped = this[c-n];
-                this.RemoveRange (c - n, n);
-                isBoxeds.RemoveRange (c - n, n);
-            }
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-            return lastPopped;
-        }
-
-        /**
-         * @brief Peek at the n'th stack value.
-         *        n = 0 : top of stack
-         *            1 : next to top
-         *                ...
-         */
-        public Type Peek (int n)
-        {
-            int c = this.Count;
-            if (n > c - 1) throw new Exception ("stack going negative");
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-            return this[c-n-1];
-        }
-        public bool PeekBoxed (int n)
-        {
-            int c = isBoxeds.Count;
-            if (n > c - 1) throw new Exception ("stack going negative");
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-            return isBoxeds[c-n-1];
-        }
-
-        /**
-         * @brief Push a single value of the given type.
-         */
-        public void Push (Type t)
-        {
-            Push (t, false);
-        }
-        public void Push (Type t, bool isBoxed)
-        {
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-            this.Add (t);
-            isBoxeds.Add (isBoxed);
-        }
-
-        /**
-         * @brief See if the types at a given label exactly match those on the stack.
-         *        We should have the stack types be the same no matter how we branched 
-         *        or fell through to a particular label.
-         */
-        public void Matches (ScriptMyLabel label)
-        {
-            Type[] ts       = label.stackDepth;
-            bool[] tsBoxeds = label.stackBoxeds;
-            int i;
-
-            if (this.Count != isBoxeds.Count) throw new Exception ("isBoxeds count bad");
-
-            if (ts == null) {
-                label.stackDepth  = this.ToArray ();
-                label.stackBoxeds = isBoxeds.ToArray ();
-            } else if (ts.Length != this.Count) {
-                throw new Exception ("stack depth mismatch");
-            } else {
-                for (i = this.Count; -- i >= 0;) {
-                    if (tsBoxeds[i] != this.isBoxeds[i]) goto mismatch;
-                    if (ts[i] == this[i]) continue;
-                    if ((ts[i]   == typeof (bool) || ts[i]   == typeof (char) || ts[i]   == typeof (int)) && 
-                        (this[i] == typeof (bool) || this[i] == typeof (char) || this[i] == typeof (int))) continue;
-                    if ((ts[i]   == typeof (double) || ts[i]   == typeof (float)) && 
-                        (this[i] == typeof (double) || this[i] == typeof (float))) continue;
-                    goto mismatch;
-                }
-            }
-            return;
-        mismatch:
-            throw new Exception ("stack type mismatch: " + StackTypeString (ts[i], tsBoxeds[i]) + " vs " + StackTypeString (this[i], this.isBoxeds[i]));
-        }
-
-        private static string StackTypeString (Type ts, bool isBoxed)
-        {
-            if (!isBoxed) return ts.Name;
-            return "[" + ts.Name + "]";
-        }
-    }
-
-    /**
-     * @brief One of these per opcode and label in the function plus other misc markers.
-     *        They form the CIL instruction stream of the function.
-     */
-    public abstract class GraphNode {
-        private static readonly bool DEBUG = false;
-
-        public const int OPINDENT =  4;
-        public const int OPDEBLEN = 12;
-
-        public ScriptCollector coll;
-        public GraphNodeBeginExceptionBlock tryBlock;  // start of enclosing try block
-                                                       // valid in the try section
-                                                       // null in the catch/finally sections
-                                                       // null outside of try block
-                                                       // for the try node itself, links to outer try block
-        public GraphNodeBeginExceptionBlock excBlock;  // start of enclosing try block
-                                                       // valid in the try/catch/finally sections
-                                                       // null outside of try/catch/finally block
-                                                       // for the try node itself, links to outer try block
-
-        /*
-         * List of nodes in order as originally given.
-         */
-        public GraphNode nextLin, prevLin;
-        public int linSeqNo;
-
-        /**
-         * @brief Save pointer to collector.
-         */
-        public GraphNode (ScriptCollector coll)
-        {
-            this.coll = coll;
-        }
-
-        /**
-         * @brief Chain graph node to end of linear list.
-         */
-        public virtual void ChainLin ()
-        {
-            coll.lastLin.nextLin = this;
-            this.prevLin  = coll.lastLin;
-            coll.lastLin  = this;
-            this.tryBlock = coll.curTryBlock;
-            this.excBlock = coll.curExcBlock;
-
-            if (DEBUG) {
-                StringBuilder sb = new StringBuilder ("ChainLin*:");
-                sb.Append (coll.stackDepth.Count.ToString("D2"));
-                sb.Append (' ');
-                this.DebString (sb);
-                Console.WriteLine (sb.ToString ());
-            }
-        }
-
-        /**
-         * @brief Append full info to debugging string for printing out the instruction.
-         */
-        public void DebStringExt (StringBuilder sb)
-        {
-            int x = sb.Length;
-            sb.Append (this.linSeqNo.ToString ().PadLeft (5));
-            sb.Append (": ");
-            this.DebString (sb);
-
-            if (this.ReadsLocal  () != null) ScriptCollector.PadToLength (sb, x + 60, " [read]");
-            if (this.WritesLocal () != null) ScriptCollector.PadToLength (sb, x + 68, " [write]");
-            ScriptCollector.PadToLength (sb, x + 72, " ->");
-            bool first = true;
-            foreach (GraphNode nn in this.NextNodes) {
-                if (first) {
-                    sb.Append (nn.linSeqNo.ToString ().PadLeft (5));
-                    first = false;
-                } else {
-                    sb.Append (',');
-                    sb.Append (nn.linSeqNo);
-                }
-            }
-        }
-
-        /**
-         * @brief See if it's possible for it to fall through to the next inline (nextLin) instruction.
-         */
-        public virtual bool CanFallThrough ()
-        {
-            return true;
-        }
-
-        /**
-         * @brief Append to debugging string for printing out the instruction.
-         */
-        public abstract void DebString (StringBuilder sb);
-        public override string ToString ()
-        {
-            StringBuilder sb = new StringBuilder ();
-            this.DebString (sb);
-            return sb.ToString ();
-        }
-
-        /**
-         * @brief See if this instruction reads a local variable.
-         */
-        public virtual ScriptMyLocal ReadsLocal  () { return null; }
-
-        /**
-         * @brief See if this instruction writes a local variable.
-         */
-        public virtual ScriptMyLocal WritesLocal () { return null; }
-
-        /**
-         * @brief Write this instruction out to the wrapped object file.
-         */
-        public abstract void WriteOutOne (ScriptMyILGen ilGen);
-
-        /**
-         * @brief Iterate through all the possible next nodes, including the next inline node, if any.
-         *        The next inline code is excluded if the instruction never falls through, eg, return, unconditional branch.
-         *        It includes a possible conditional branch to the beginning of the corresponding catch/finally of every 
-         *        instruction in a try section.
-         */
-        private System.Collections.Generic.IEnumerable<GraphNode> nextNodes, nextNodesCatchFinally;
-        public System.Collections.Generic.IEnumerable<GraphNode> NextNodes
-        { get {
-            if (nextNodes == null) {
-                nextNodes = GetNNEnumerable ();
-                nextNodesCatchFinally = new NNEnumerableCatchFinally (this);
-            }
-            return nextNodesCatchFinally;
-        } }
-
-        /**
-         * @brief This acts as a wrapper around all the other NNEnumerable's below.
-         *        It assumes every instruction in a try { } can throw an exception so it 
-         *        says that every instruction in a try { } can conditionally branch to 
-         *        the beginning of the corresponding catch { } or finally { }.
-         */
-        private class NNEnumerableCatchFinally : System.Collections.Generic.IEnumerable<GraphNode> {
-            private GraphNode gn;
-            public NNEnumerableCatchFinally (GraphNode gn)
-            {
-                this.gn = gn;
-            }
-            System.Collections.Generic.IEnumerator<GraphNode> System.Collections.Generic.IEnumerable<GraphNode>.GetEnumerator ()
-            {
-                return new NNEnumeratorCatchFinally (gn);
-            }
-            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
-            {
-                return new NNEnumeratorCatchFinally (gn);
-            }
-        }
-        private class NNEnumeratorCatchFinally : NNEnumeratorBase {
-            private GraphNode gn;
-            private int index = 0;
-            private System.Collections.Generic.IEnumerator<GraphNode> realEnumerator;
-            public NNEnumeratorCatchFinally (GraphNode gn)
-            {
-                this.gn = gn;
-                this.realEnumerator = gn.nextNodes.GetEnumerator ();
-            }
-            public override bool MoveNext ()
-            {
-                /*
-                 * First off, return any targets the instruction can come up with.
-                 */
-                if (realEnumerator.MoveNext ()) {
-                    nn = realEnumerator.Current;
-                    return true;
-                }
-
-                /*
-                 * Then if this instruction is in a try section, say this instruction 
-                 * can potentially branch to the beginning of the corresponding 
-                 * catch/finally.
-                 */
-                if ((index == 0) && (gn.tryBlock != null)) {
-                    index ++;
-                    nn = gn.tryBlock.catchFinallyBlock;
-                    return true;
-                }
-
-                /*
-                 * That's all we can do.
-                 */
-                nn = null;
-                return false;
-            }
-            public override void Reset ()
-            {
-                realEnumerator.Reset ();
-                index = 0;
-                nn = null;
-            }
-        }
-
-        /**
-         * @brief This default iterator always returns the next inline node as the one-and-only next node.
-         *        Other instructions need to override it if they can possibly do other than that.
-         */
-
-        /**
-         * @brief GetNNEnumerable() gets the nextnode enumerable part of a GraphNode,
-         *        which in turn gives the list of nodes that can possibly be next in 
-         *        a flow-control sense.  It simply instantiates the NNEnumerator sub-
-         *        class which does the actual enumeration.
-         */
-        protected virtual System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNode gn;
-            private int index;
-            public NNEnumerator (GraphNode gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                switch (index) {
-                    case 0: {
-                        index ++;
-                        nn = gn.nextLin;
-                        return nn != null;
-                    }
-                    case 1: {
-                        nn = null;
-                        return false;
-                    }
-                }
-                throw new Exception ();
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    /**
-     * @brief Things that derive from this are the beginning of a block.
-     *        A block of code is that which begins with a label or is the beginning of all code
-     *        and it contains no labels, ie, it can't be jumped into other than at its beginning.
-     */
-    public abstract class GraphNodeBlock : GraphNode {
-        public List<ScriptMyLocal> localsWrittenBeforeRead = new List<ScriptMyLocal> ();
-        public List<ScriptMyLocal> localsReadBeforeWritten = new List<ScriptMyLocal> ();
-        public int hasBeenResolved;
-        public GraphNodeBlock (ScriptCollector coll) : base (coll) { }
-    }
-
-    /**
-     * @brief This placeholder is at the beginning of the code so the first few instructions 
-     *        belong to some block.
-     */
-    public class GraphNodeBegin : GraphNodeBlock {
-        public GraphNodeBegin (ScriptCollector coll) : base (coll) { }
-        public override void DebString (StringBuilder sb) { sb.Append ("begin"); }
-        public override void WriteOutOne (ScriptMyILGen ilGen) { }
-    }
-
-    /**
-     * @brief Beginning of try block.
-     */
-    public class GraphNodeBeginExceptionBlock : GraphNodeBlock {
-        public GraphNodeBeginExceptionBlock outerTryBlock;      // next outer try opcode or null
-        public GraphNodeCatchFinallyBlock   catchFinallyBlock;  // start of associated catch or finally
-        public GraphNodeEndExceptionBlock   endExcBlock;        // end of associated catch or finally
-        public int excBlkSeqNo;                                 // debugging
-
-        public GraphNodeBeginExceptionBlock (ScriptCollector coll) : base (coll)
-        { }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // we should always start try blocks with nothing on stack
-            // ...as CLI wipes stack for various conditions
-            if (coll.stackDepth.Count != 0) {
-                throw new Exception ("stack depth " + coll.stackDepth.Count);
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append ("  beginexceptionblock_");
-            sb.Append (excBlkSeqNo);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.BeginExceptionBlock ();
-        }
-    }
-
-    /**
-     * @brief Beginning of catch or finally block.
-     */
-    public abstract class GraphNodeCatchFinallyBlock : GraphNodeBlock {
-        public GraphNodeCatchFinallyBlock (ScriptCollector coll) : base (coll)
-        { }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // we should always start catch/finally blocks with nothing on stack
-            // ...as CLI wipes stack for various conditions
-            if (coll.stackDepth.Count != 0) {
-                throw new Exception ("stack depth " + coll.stackDepth.Count);
-            }
-        }
-    }
-
-    /**
-     * @brief Beginning of catch block.
-     */
-    public class GraphNodeBeginCatchBlock : GraphNodeCatchFinallyBlock {
-        public Type excType;
-
-        public GraphNodeBeginCatchBlock (ScriptCollector coll, Type excType) : base (coll)
-        {
-            this.excType = excType;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // catch block always enters with one value on stack
-            if (coll.stackDepth.Count != 0) {
-                throw new Exception ("stack depth " + coll.stackDepth.Count);
-            }
-            coll.stackDepth.Push (excType);
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append ("  begincatchblock_");
-            sb.Append (excBlock.excBlkSeqNo);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.BeginCatchBlock (excType);
-        }
-
-        /**
-         * @brief The beginning of every catch { } conditinally branches to the beginning 
-         *        of all outer catch { }s up to and including the next outer finally { }.
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeBeginCatchBlock gn;
-            private int index;
-            public NNEnumerator (GraphNodeBeginCatchBlock gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                while (true) {
-                    switch (index) {
-                        case 0: {
-                            // start with the fallthru
-                            nn = gn.nextLin;
-                            index ++;
-                            return true;
-                        }
-
-                        case 1: {
-                            // get the first outer catch { } or finally { }
-                            // pretend we last returned beginning of this catch { }
-                            // then loop back to get next outer catch { } or finally { }
-                            nn = gn;
-                            break;
-                        }
-
-                        case 2: {
-                            // nn points to a catch { } previously returned
-                            // get the corresponding try { }
-                            GraphNodeBeginExceptionBlock nntry = nn.excBlock;
-
-                            // step out to next outer try { }
-                            nntry = nntry.excBlock;
-                            if (nntry == null) break;
-
-                            // return corresponding catch { } or finally { }
-                            nn = nntry.catchFinallyBlock;
-
-                            // if it's a finally { } we don't do anything after that
-                            if (nn is GraphNodeBeginFinallyBlock) index ++;
-                            return true;
-                        }
-
-                        case 3: {
-                            // we've returned the fallthru, catches and one finally
-                            // so there's nothing more to say
-                            nn = null;
-                            return false;
-                        }
-
-                        default: throw new Exception ();
-                    }
-                    index ++;
-                }
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    /**
-     * @brief Beginning of finally block.
-     */
-    public class GraphNodeBeginFinallyBlock : GraphNodeCatchFinallyBlock {
-
-        // leaveTargets has a list of all the targets of any contained 
-        // leave instructions, ie, where an endfinally can possibly jump.
-        // But only those targets within the next outer finally { }, we 
-        // don't contain any targets outside of that, those targets are 
-        // stored in the actual finally that will jump to the target.
-        // The endfinally enumerator assumes that it is always possible 
-        // for it to jump to the next outer finally (as would happen for
-        // an uncaught exception), so no need to do anything special.
-        public List<GraphNodeBlock> leaveTargets = new List<GraphNodeBlock> ();
-
-        public GraphNodeBeginFinallyBlock (ScriptCollector coll) : base (coll)
-        { }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append ("  beginfinallyblock_");
-            sb.Append (excBlock.excBlkSeqNo);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.BeginFinallyBlock ();
-        }
-    }
-
-    /**
-     * @brief End of try/catch/finally block.
-     */
-    public class GraphNodeEndExceptionBlock : GraphNode {
-        public GraphNodeEndExceptionBlock (ScriptCollector coll) : base (coll)
-        { }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // we should always end exception blocks with nothing on stack
-            // ...as CLI wipes stack for various conditions
-            if (coll.stackDepth.Count != 0) {
-                throw new Exception ("stack depth " + coll.stackDepth.Count);
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append ("  endexceptionblock_");
-            sb.Append (excBlock.excBlkSeqNo);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.EndExceptionBlock ();
-        }
-    }
-
-    /**
-     * @brief Actual instruction emits...
-     */
-    public abstract class GraphNodeEmit : GraphNode {
-        public OpCode opcode;
-        public Token errorAt;
-
-        public GraphNodeEmit (ScriptCollector coll, Token errorAt, OpCode opcode) : base (coll)
-        {
-            this.opcode  = opcode;
-            this.errorAt = errorAt;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // compute resultant stack depth
-            int stack = coll.stackDepth.Count;
-
-            if ((stack != 0) && ((opcode == OpCodes.Endfinally) || (opcode == OpCodes.Leave) || (opcode == OpCodes.Rethrow))) {
-                throw new Exception (opcode + " stack depth " + stack);
-            }
-            if ((stack != 1) && (opcode == OpCodes.Throw)) {
-                throw new Exception (opcode + " stack depth " + stack);
-            }
-        }
-
-        /**
-         * @brief See if it's possible for it to fall through to the next inline (nextLin) instruction.
-         */
-        public override bool CanFallThrough ()
-        {
-            switch (opcode.FlowControl) {
-                case FlowControl.Branch:      return false;  // unconditional branch
-                case FlowControl.Break:       return true;   // break
-                case FlowControl.Call:        return true;   // call
-                case FlowControl.Cond_Branch: return true;   // conditional branch
-                case FlowControl.Next:        return true;   // falls through to next instruction
-                case FlowControl.Return:      return false;  // return
-                case FlowControl.Throw:       return false;  // throw
-                default: {
-                    string op = opcode.ToString ();
-                    if (op == "volatile.") return true;
-                    throw new Exception ("unknown flow control " + opcode.FlowControl + " for " + op);
-                }
-            }
-        }
-
-        // if followed by OpCodes.Pop, it can be discarded
-        public bool isPoppable
-        { get {
-            return
-                ((opcode.StackBehaviourPop  == StackBehaviour.Pop0) &&    // ldarg,ldloc,ldsfld
-                 (opcode.StackBehaviourPush == StackBehaviour.Push1)) || 
-                ((opcode.StackBehaviourPop  == StackBehaviour.Pop0) &&    // ldarga,ldloca,ldc,ldsflda,...
-                 (opcode.StackBehaviourPush == StackBehaviour.Pushi)) || 
-                (opcode == OpCodes.Ldnull) || 
-                (opcode == OpCodes.Ldc_R4) || 
-                (opcode == OpCodes.Ldc_R8) || 
-                (opcode == OpCodes.Ldstr)  || 
-                (opcode == OpCodes.Ldc_I8) || 
-                (opcode == OpCodes.Dup);
-        } }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append ("".PadRight (OPINDENT));
-            sb.Append (opcode.ToString ().PadRight (OPDEBLEN));
-        }
-
-        /**
-         * @brief If instruction is terminating, we say there is nothing following (eg, return).
-         *        Otherwise, say the one-and-only next instruction is the next instruction inline.
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeEmit gn;
-            private int index;
-            public NNEnumerator (GraphNodeEmit gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                switch (index) {
-                    case 0: {
-                        if (gn.CanFallThrough ()) {
-                            index ++;
-                            nn = gn.nextLin;
-                            return nn != null;
-                        }
-                        return false;
-                    }
-                    case 1: {
-                        nn = null;
-                        return false;
-                    }
-                }
-                throw new Exception ();
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    public class GraphNodeEmitNull : GraphNodeEmit {
-        public GraphNodeEmitNull (ScriptCollector coll, Token errorAt, OpCode opcode) : base (coll, errorAt, opcode)
-        { }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "nop": break;
-                case "break": break;
-                case "volatile.": break;
-                case "ldarg.0": coll.stackDepth.Push (coll.wrapped.argTypes[0]); break;
-                case "ldarg.1": coll.stackDepth.Push (coll.wrapped.argTypes[1]); break;
-                case "ldarg.2": coll.stackDepth.Push (coll.wrapped.argTypes[2]); break;
-                case "ldarg.3": coll.stackDepth.Push (coll.wrapped.argTypes[3]); break;
-                case "ldnull":  coll.stackDepth.Push (null); break;
-                case "ldc.i4.m1":
-                case "ldc.i4.0":
-                case "ldc.i4.1":
-                case "ldc.i4.2":
-                case "ldc.i4.3":
-                case "ldc.i4.4":
-                case "ldc.i4.5":
-                case "ldc.i4.6":
-                case "ldc.i4.7":
-                case "ldc.i4.8": {
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "dup": {
-                    Type t = coll.stackDepth.Peek (0);
-                    bool b = coll.stackDepth.PeekBoxed (0);
-                    coll.stackDepth.Push (t, b);
-                    break;
-                }
-                case "pop": {
-                    coll.stackDepth.Pop (1);
-                    break;
-                }
-                case "ret": {
-                    int sd = (coll.wrapped.retType != typeof (void)) ? 1 : 0;
-                    if (coll.stackDepth.Count != sd) throw new Exception ("bad stack depth");
-                    if (sd > 0) {
-                        coll.stackDepth.Pop (coll.wrapped.retType);
-                    }
-                    break;
-                }
-                case "add":
-                case "sub":
-                case "mul":
-                case "div":
-                case "div.un":
-                case "rem":
-                case "rem.un":
-                case "and":
-                case "or":
-                case "xor":
-                case "shl":
-                case "shr":
-                case "shr.un":
-                case "add.ovf":
-                case "add.ovf.un":
-                case "mul.ovf":
-                case "mul.ovf.un":
-                case "sub.ovf":
-                case "sub.ovf.un": {
-                    coll.stackDepth.PopNumVal ();
-                    Type t = coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.Push (t);
-                    break;
-                }
-                case "neg":
-                case "not": {
-                    Type t = coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.Push (t);
-                    break;
-                }
-                case "conv.i1":
-                case "conv.i2":
-                case "conv.i4":
-                case "conv.i8":
-                case "conv.r4":
-                case "conv.r8":
-                case "conv.u4":
-                case "conv.u8":
-                case "conv.r.un":
-                case "conv.ovf.i1.un":
-                case "conv.ovf.i2.un":
-                case "conv.ovf.i4.un":
-                case "conv.ovf.i8.un":
-                case "conv.ovf.u1.un":
-                case "conv.ovf.u2.un":
-                case "conv.ovf.u4.un":
-                case "conv.ovf.u8.un":
-                case "conv.ovf.i.un":
-                case "conv.ovf.u.un":
-                case "conv.ovf.i1":
-                case "conv.ovf.u1":
-                case "conv.ovf.i2":
-                case "conv.ovf.u2":
-                case "conv.ovf.i4":
-                case "conv.ovf.u4":
-                case "conv.ovf.i8":
-                case "conv.ovf.u8":
-                case "conv.u2":
-                case "conv.u1":
-                case "conv.i":
-                case "conv.ovf.i":
-                case "conv.ovf.u":
-                case "conv.u": {
-                    coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.Push (ConvToType (opcode));
-                    break;
-                }
-                case "throw": {
-                    if (coll.stackDepth.Count != 1) throw new Exception ("bad stack depth " + coll.stackDepth.Count);
-                    coll.stackDepth.PopRef ();
-                    break;
-                }
-                case "ldlen": {
-                    coll.stackDepth.Pop (typeof (string));
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "ldelem.i1":
-                case "ldelem.u1":
-                case "ldelem.i2":
-                case "ldelem.u2":
-                case "ldelem.i4":
-                case "ldelem.u4":
-                case "ldelem.i8":
-                case "ldelem.i":
-                case "ldelem.r4":
-                case "ldelem.r8":
-                case "ldelem.ref": {
-                    Type t = coll.stackDepth.Peek (1).GetElementType ();
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (t.MakeArrayType ());
-                    coll.stackDepth.Push (t);
-                    break;
-                }
-                case "stelem.i":
-                case "stelem.i1":
-                case "stelem.i2":
-                case "stelem.i4":
-                case "stelem.i8":
-                case "stelem.r4":
-                case "stelem.r8":
-                case "stelem.ref": {
-                    Type t = coll.stackDepth.Peek (2).GetElementType ();
-                    coll.stackDepth.Pop (t);
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (t.MakeArrayType ());
-                    break;
-                }
-                case "endfinally":
-                case "rethrow": {
-                    if (coll.stackDepth.Count != 0) throw new Exception ("bad stack depth " + coll.stackDepth.Count);
-                    break;
-                }
-                case "ceq": {
-                    Type t = coll.stackDepth.Pop (1);
-                    if (t == null) {
-                        coll.stackDepth.PopRef ();
-                    } else {
-                        coll.stackDepth.Pop (t);
-                    }
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "cgt":
-                case "cgt.un":
-                case "clt":
-                case "clt.un": {
-                    coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "ldind.i4": {
-                    coll.stackDepth.Pop (typeof (int).MakeByRefType ());
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "stind.i4": {
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (typeof (int).MakeByRefType ());
-                    break;
-                }
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        private static Type ConvToType (OpCode opcode)
-        {
-            string s = opcode.ToString ();
-            s = s.Substring (5);  // strip off "conv."
-            if (s.StartsWith ("ovf.")) s = s.Substring (4);
-            if (s.EndsWith (".un")) s = s.Substring (0, s.Length - 3);
-
-            switch (s) {
-                case "i":  return typeof (IntPtr);
-                case "i1": return typeof (sbyte);
-                case "i2": return typeof (short);
-                case "i4": return typeof (int);
-                case "i8": return typeof (long);
-                case "r":
-                case "r4": return typeof (float);
-                case "r8": return typeof (double);
-                case "u1": return typeof (byte);
-                case "u2": return typeof (ushort);
-                case "u4": return typeof (uint);
-                case "u8": return typeof (ulong);
-                case "u":  return typeof (UIntPtr);
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode);
-        }
-    }
-
-    public class GraphNodeEmitNullEndfinally : GraphNodeEmitNull {
-        public GraphNodeEmitNullEndfinally (ScriptCollector coll, Token errorAt) : base (coll, errorAt, OpCodes.Endfinally)
-        { }
-
-        /**
-         * @brief Endfinally can branch to:
-         *          1) the corresponding EndExceptionBlock
-         *          2) any of the corresponding BeginFinallyBlock's leaveTargets
-         *          3) the next outer BeginFinallyBlock
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeEmitNullEndfinally gn;
-            private IEnumerator<GraphNodeBlock> leaveTargetEnumerator;
-            private int index;
-            public NNEnumerator (GraphNodeEmitNullEndfinally gn)
-            {
-                this.gn = gn;
-
-                // endfinally instruction must be within some try/catch/finally mess
-                GraphNodeBeginExceptionBlock thistry = gn.excBlock;
-
-                // endfinally instruction must be within some finally { } mess
-                GraphNodeBeginFinallyBlock thisfin = (GraphNodeBeginFinallyBlock)thistry.catchFinallyBlock;
-
-                // get the list of the finally { } leave instruction targets
-                this.leaveTargetEnumerator = thisfin.leaveTargets.GetEnumerator ();
-            }
-            public override bool MoveNext ()
-            {
-                while (true) {
-                    switch (index) {
-
-                        // to start, return end of our finally { }
-                        case 0: {
-                            GraphNodeBeginExceptionBlock thistry = gn.excBlock;
-                            nn = thistry.endExcBlock;
-                            if (nn == null) throw new NullReferenceException ("thistry.endExcBlock");
-                            index ++;
-                            return true;
-                        }
-
-                        // return next one of our finally { }'s leave targets
-                        // ie, where any leave instructions in the try { } want 
-                        // the finally { } to go to when it finishes
-                        case 1: {
-                            if (this.leaveTargetEnumerator.MoveNext ()) {
-                                nn = this.leaveTargetEnumerator.Current;
-                                if (nn == null) throw new NullReferenceException ("this.leaveTargetEnumerator.Current");
-                                return true;
-                            }
-                            break;
-                        }
-
-                        // return beginning of next outer finally { }
-                        case 2: {
-                            GraphNodeBeginExceptionBlock nntry = gn.excBlock;
-                            while ((nntry = nntry.excBlock) != null) {
-                                if (nntry.catchFinallyBlock is GraphNodeBeginFinallyBlock) {
-                                    nn = nntry.catchFinallyBlock;
-                                    if (nn == null) throw new NullReferenceException ("nntry.catchFinallyBlock");
-                                    index ++;
-                                    return true;
-                                }
-                            }
-                            break;
-                        }
-
-                        // got nothing more
-                        case 3: {
-                            return false;
-                        }
-
-                        default: throw new Exception ();
-                    }
-                    index ++;
-                }
-            }
-            public override void Reset ()
-            {
-                leaveTargetEnumerator.Reset ();
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    public class GraphNodeEmitField : GraphNodeEmit {
-        public FieldInfo field;
-
-        public GraphNodeEmitField (ScriptCollector coll, Token errorAt, OpCode opcode, FieldInfo field) : base (coll, errorAt, opcode)
-        {
-            this.field = field;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldfld":   PopPointer ();                         coll.stackDepth.Push (field.FieldType);                  break;
-                case "ldflda":  PopPointer ();                         coll.stackDepth.Push (field.FieldType.MakeByRefType ()); break;
-                case "stfld":   coll.stackDepth.Pop (field.FieldType); PopPointer ();                                           break;
-                case "ldsfld":                                         coll.stackDepth.Push (field.FieldType);                  break;
-                case "ldsflda":                                        coll.stackDepth.Push (field.FieldType.MakeByRefType ()); break;
-                case "stsfld":                                         coll.stackDepth.Pop  (field.FieldType);                  break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-        private void PopPointer ()
-        {
-            Type t = field.DeclaringType;               // get class/field type
-            if (t.IsValueType) {
-                Type brt = t.MakeByRefType ();      // if value type, eg Vector, it can be pushed by reference or by value
-                int c = coll.stackDepth.Count;
-                if ((c > 0) && (coll.stackDepth[c-1] == brt)) t = brt;
-            }
-            coll.stackDepth.Pop (t);                    // type of what should be on the stack pointing to object or struct
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (field.Name);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, field);
-        }
-    }
-
-    public class GraphNodeEmitLocal : GraphNodeEmit {
-        public ScriptMyLocal myLocal;
-
-        public GraphNodeEmitLocal (ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLocal myLocal) : base (coll, errorAt, opcode)
-        {
-            this.myLocal = myLocal;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldloc":  coll.stackDepth.Push (myLocal.type); break;
-                case "ldloca": coll.stackDepth.Push (myLocal.type.MakeByRefType ()); break;
-                case "stloc":  coll.stackDepth.Pop  (myLocal.type); break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (myLocal.name);
-        }
-
-        public override ScriptMyLocal ReadsLocal  ()
-        {
-            if (opcode == OpCodes.Ldloc)  return myLocal;
-            if (opcode == OpCodes.Ldloca) return myLocal;
-            if (opcode == OpCodes.Stloc)  return null;
-            throw new Exception ("unknown opcode " + opcode);
-        }
-        public override ScriptMyLocal WritesLocal ()
-        {
-            if (opcode == OpCodes.Ldloc)  return null;
-            if (opcode == OpCodes.Ldloca) return myLocal;
-            if (opcode == OpCodes.Stloc)  return myLocal;
-            throw new Exception ("unknown opcode " + opcode);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, myLocal);
-        }
-    }
-
-    public class GraphNodeEmitType : GraphNodeEmit {
-        public Type type;
-
-        public GraphNodeEmitType (ScriptCollector coll, Token errorAt, OpCode opcode, Type type) : base (coll, errorAt, opcode)
-        {
-            this.type = type;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "castclass":
-                case "isinst": {
-                    coll.stackDepth.PopRef ();
-                    coll.stackDepth.Push (type, type.IsValueType);
-                    break;
-                }
-                case "box": {
-                    if (!type.IsValueType) throw new Exception ("can't box a non-value type");
-                    coll.stackDepth.Pop (type);
-                    coll.stackDepth.Push (type, true);
-                    break;
-                }
-                case "unbox":
-                case "unbox.any": {
-                    if (!type.IsValueType) throw new Exception ("can't unbox to a non-value type");
-                    coll.stackDepth.PopRef ();
-                    coll.stackDepth.Push (type);
-                    break;
-                }
-                case "newarr": {
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Push (type.MakeArrayType ());
-                    break;
-                }
-                case "sizeof": {
-                    coll.stackDepth.Pop (1);
-                    coll.stackDepth.Push (typeof (int));
-                    break;
-                }
-                case "ldelem": {
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (type.MakeArrayType ());
-                    coll.stackDepth.Push (type);
-                    break;
-                }
-                case "ldelema": {
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (type.MakeArrayType ());
-                    coll.stackDepth.Push (type.MakeByRefType ());
-                    break;
-                }
-                case "stelem": {
-                    coll.stackDepth.Pop (type);
-                    coll.stackDepth.Pop (typeof (int));
-                    coll.stackDepth.Pop (type.MakeArrayType ());
-                    break;
-                }
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (type.Name);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, type);
-        }
-    }
-
-    public class GraphNodeEmitLabel : GraphNodeEmit {
-        public ScriptMyLabel myLabel;
-
-        public GraphNodeEmitLabel (ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLabel myLabel) : base (coll, errorAt, opcode)
-        {
-            this.myLabel = myLabel;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "brfalse.s":
-                case "brtrue.s":
-                case "brfalse":
-                case "brtrue": {
-                    coll.stackDepth.Pop (1);
-                    break;
-                }
-                case "beq.s":
-                case "bge.s":
-                case "bgt.s":
-                case "ble.s":
-                case "blt.s":
-                case "bne.un.s":
-                case "bge.un.s":
-                case "bgt.un.s":
-                case "ble.un.s":
-                case "blt.un.s":
-                case "beq":
-                case "bge":
-                case "bgt":
-                case "ble":
-                case "blt":
-                case "bne.un":
-                case "bge.un":
-                case "bgt.un":
-                case "ble.un":
-                case "blt.un": {
-                    coll.stackDepth.PopNumVal ();
-                    coll.stackDepth.PopNumVal ();
-                    break;
-                }
-                case "br":
-                case "br.s": break;
-                case "leave": {
-                    if (coll.stackDepth.Count != 0) throw new Exception ("bad stack depth " + coll.stackDepth.Count);
-                    break;
-                }
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-
-            // if a target doesn't have a depth yet, set its depth to the depth after instruction executes
-            // otherwise, make sure it matches all other branches to that target and what fell through to it
-            coll.stackDepth.Matches (myLabel);
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (myLabel.name);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, myLabel);
-        }
-
-        /**
-         * @brief Conditional branches return the next inline followed by the branch target
-         *        Unconditional branches return only the branch target
-         *        But if the target is outside our scope (eg __retlbl), omit it from the list
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeEmitLabel gn;
-            private int index;
-            public NNEnumerator (GraphNodeEmitLabel gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                switch (gn.opcode.FlowControl) {
-                    case FlowControl.Branch: {
-                        // unconditional branch just goes to target and nothing else
-                        switch (index) {
-                            case 0: {
-                                nn = gn.myLabel.whereAmI;
-                                index ++;
-                                return nn != null;
-                            }
-                            case 1: {
-                                return false;
-                            }
-                        }
-                        throw new Exception ();
-                    }
-                    case FlowControl.Cond_Branch: {
-                        // conditional branch goes inline and to target
-                        switch (index) {
-                            case 0: {
-                                nn = gn.nextLin;
-                                index ++;
-                                return true;
-                            }
-                            case 1: {
-                                nn = gn.myLabel.whereAmI;
-                                index ++;
-                                return nn != null;
-                            }
-                            case 2: {
-                                return false;
-                            }
-                        }
-                        throw new Exception ();
-                    }
-                    default: throw new Exception ("unknown flow control " + gn.opcode.FlowControl.ToString () + 
-                                                  " of " + gn.opcode.ToString ());
-                }
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    public class GraphNodeEmitLabelLeave : GraphNodeEmitLabel {
-        public GraphNodeBlock unwindTo;  // if unwinding, innermost finally block being unwound
-                                         //         else, same as myTarget.whereAmI
-                                         // null if unwinding completely out of scope, eg, __retlbl
-
-        public GraphNodeEmitLabelLeave (ScriptCollector coll, Token errorAt, ScriptMyLabel myLabel) : base (coll, errorAt, OpCodes.Leave, myLabel)
-        { }
-
-        /**
-         * @brief Leave instructions have exactly one unconditional next node.
-         *        Either the given target if within the same try block 
-         *        or the beginning of the intervening finally block.
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeEmitLabelLeave gn;
-            private int index;
-            public NNEnumerator (GraphNodeEmitLabelLeave gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                if (index == 0) {
-                    nn = gn.unwindTo;
-                    index ++;
-                    return nn != null;
-                }
-                nn = null;
-                return false;
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    public class GraphNodeEmitLabels : GraphNodeEmit {
-        public ScriptMyLabel[] myLabels;
-
-        public GraphNodeEmitLabels (ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels) : base (coll, errorAt, opcode)
-        {
-            this.myLabels = myLabels;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "switch": {
-                    coll.stackDepth.Pop (typeof (int));
-                    break;
-                }
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-
-            // if a target doesn't have a depth yet, set its depth to the depth after instruction executes
-            // otherwise, make sure it matches all other branches to that target and what fell through to it
-            foreach (ScriptMyLabel myLabel in myLabels) {
-                coll.stackDepth.Matches (myLabel);
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            bool first = true;
-            foreach (ScriptMyLabel lbl in myLabels) {
-                if (!first) sb.Append (',');
-                sb.Append (lbl.name);
-                first = false;
-            }
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, myLabels);
-        }
-
-        /**
-         * @brief Return list of all labels followed by the next linear instruction
-         *        But if the target is outside our scope (eg __retlbl), omit it from the list
-         */
-        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable ()
-        {
-            return new NNEnumerable (this, typeof (NNEnumerator));
-        }
-
-        private class NNEnumerator : NNEnumeratorBase {
-            private GraphNodeEmitLabels gn;
-            private int index;
-            public NNEnumerator (GraphNodeEmitLabels gn)
-            {
-                this.gn = gn;
-            }
-            public override bool MoveNext ()
-            {
-                /*
-                 * Return next from list of switch case labels.
-                 */
-                while (index < gn.myLabels.Length) {
-                    nn = gn.myLabels[index++].whereAmI;
-                    if (nn != null) return true;
-                }
-
-                /*
-                 * If all ran out, the switch instruction falls through.
-                 */
-                if (index == gn.myLabels.Length) {
-                    index ++;
-                    nn = gn.nextLin;
-                    return true;
-                }
-
-                /*
-                 * Even ran out of that, say there's nothing more.
-                 */
-                nn = null;
-                return false;
-            }
-            public override void Reset ()
-            {
-                index = 0;
-                nn = null;
-            }
-        }
-    }
-
-    public class GraphNodeEmitIntMeth : GraphNodeEmit {
-        public ScriptObjWriter method;
-
-        public GraphNodeEmitIntMeth (ScriptCollector coll, Token errorAt, OpCode opcode, ScriptObjWriter method) : base (coll, errorAt, opcode)
-        {
-            this.method = method;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "call": {
-
-                    // calls have Varpop so pop the number of arguments
-                    // they are all static so there is no separate 'this' parameter
-                    coll.stackDepth.Pop (this.method.argTypes);
-
-                    // calls are also Varpush so they push a return value iff non-void
-                    if (this.method.retType != typeof (void)) coll.stackDepth.Push (this.method.retType);
-                    break;
-                }
-
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (method.methName);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, method);
-        }
-    }
-
-    public class GraphNodeEmitExtMeth : GraphNodeEmit {
-        public MethodInfo method;
-
-        public GraphNodeEmitExtMeth (ScriptCollector coll, Token errorAt, OpCode opcode, MethodInfo method) : base (coll, errorAt, opcode)
-        {
-            this.method = method;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "call":
-                case "callvirt": {
-
-                    // calls have Varpop so pop the number of arguments
-                    coll.stackDepth.Pop (this.method.GetParameters ());
-                    if ((this.method.CallingConvention & CallingConventions.HasThis) != 0) {
-                        coll.stackDepth.Pop (method.DeclaringType);
-                    }
-
-                    // calls are also Varpush so they push a return value iff non-void
-                    if (this.method.ReturnType != typeof (void)) coll.stackDepth.Push (this.method.ReturnType);
-                    break;
-                }
-
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (method.Name);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, method);
-        }
-    }
-
-    public class GraphNodeEmitCtor : GraphNodeEmit {
-        public ConstructorInfo ctor;
-
-        public GraphNodeEmitCtor (ScriptCollector coll, Token errorAt, OpCode opcode, ConstructorInfo ctor) : base (coll, errorAt, opcode)
-        {
-            this.ctor = ctor;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "newobj": {
-                    coll.stackDepth.Pop (ctor.GetParameters ());
-                    coll.stackDepth.Push (ctor.DeclaringType);
-                    break;
-                }
-
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (ctor.ReflectedType.Name);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, ctor);
-        }
-    }
-
-    public class GraphNodeEmitDouble : GraphNodeEmit {
-        public double value;
-
-        public GraphNodeEmitDouble (ScriptCollector coll, Token errorAt, OpCode opcode, double value) : base (coll, errorAt, opcode)
-        {
-            this.value = value;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldc.r8": coll.stackDepth.Push (typeof (double)); break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (value);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, value);
-        }
-    }
-
-    public class GraphNodeEmitFloat : GraphNodeEmit {
-        public float value;
-
-        public GraphNodeEmitFloat (ScriptCollector coll, Token errorAt, OpCode opcode, float value) : base (coll, errorAt, opcode)
-        {
-            this.value = value;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldc.r4": coll.stackDepth.Push (typeof (float)); break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (value);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, value);
-        }
-    }
-
-    public class GraphNodeEmitInt : GraphNodeEmit {
-        public int value;
-
-        public GraphNodeEmitInt (ScriptCollector coll, Token errorAt, OpCode opcode, int value) : base (coll, errorAt, opcode)
-        {
-            this.value = value;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldarg":
-                case "ldarg.s":  coll.stackDepth.Push (coll.wrapped.argTypes[value]);                  break;
-                case "ldarga":
-                case "ldarga.s": coll.stackDepth.Push (coll.wrapped.argTypes[value].MakeByRefType ()); break;
-                case "starg":
-                case "starg.s":  coll.stackDepth.Pop  (coll.wrapped.argTypes[value]);                  break;
-                case "ldc.i4":
-                case "ldc.i4.s": coll.stackDepth.Push (typeof (int));                                  break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append (value);
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, value);
-        }
-    }
-
-    public class GraphNodeEmitString : GraphNodeEmit {
-        public string value;
-
-        public GraphNodeEmitString (ScriptCollector coll, Token errorAt, OpCode opcode, string value) : base (coll, errorAt, opcode)
-        {
-            this.value = value;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            switch (opcode.ToString ()) {
-                case "ldstr": coll.stackDepth.Push (typeof (string)); break;
-                default: throw new Exception ("unknown opcode " + opcode.ToString ());
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            base.DebString (sb);
-            sb.Append ("\"");
-            sb.Append (value);
-            sb.Append ("\"");
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.Emit (errorAt, opcode, value);
-        }
-    }
-
-    public class GraphNodeMarkLabel : GraphNodeBlock {
-        public ScriptMyLabel myLabel;
-
-        public GraphNodeMarkLabel (ScriptCollector coll, ScriptMyLabel myLabel) : base (coll)
-        {
-            this.myLabel = myLabel;
-        }
-
-        public override void ChainLin ()
-        {
-            base.ChainLin ();
-
-            // if previous instruction can fall through to this label,
-            //     if the label doesn't yet have a stack depth, mark it with current stack depth
-            //     else, the label's stack depth from forward branches and current stack depth must match
-            // else,
-            //     label must have had a forward branch to it so we can know stack depth
-            //     set the current stack depth to the label's stack depth as of that forward branch
-            if (myLabel.whereAmI.prevLin.CanFallThrough ()) {
-                coll.stackDepth.Matches (myLabel);
-            } else {
-                if (myLabel.stackDepth == null) {
-                    throw new Exception ("stack depth unknown at " + myLabel.name);
-                }
-                coll.stackDepth.Clear ();
-                int n = myLabel.stackDepth.Length;
-                for (int i = 0; i < n; i ++) {
-                    coll.stackDepth.Push (myLabel.stackDepth[i], myLabel.stackBoxeds[i]);
-                }
-            }
-        }
-
-        public override void DebString (StringBuilder sb)
-        {
-            sb.Append (myLabel.name);
-            sb.Append (':');
-            if (myLabel.stackDepth != null) {
-                sb.Append ("  [");
-                sb.Append (myLabel.stackDepth.Length);
-                sb.Append (']');
-            }
-        }
-
-        public override void WriteOutOne (ScriptMyILGen ilGen)
-        {
-            ilGen.MarkLabel (myLabel);
-        }
-    }
-
-
-    /**
-     * @brief Generates enumerator that steps through list of nodes that can
-     *        possibly be next in a flow-control sense.
-     */
-    public class NNEnumerable : System.Collections.Generic.IEnumerable<GraphNode> {
-        private object[] cps;
-        private ConstructorInfo ci;
-
-        public NNEnumerable (GraphNode gn, Type nnEnumeratorType)
-        {
-            this.cps = new object[] { gn };
-            this.ci  = nnEnumeratorType.GetConstructor (new Type[] { gn.GetType () });
-        }
-        System.Collections.Generic.IEnumerator<GraphNode> System.Collections.Generic.IEnumerable<GraphNode>.GetEnumerator ()
-        {
-            return (System.Collections.Generic.IEnumerator<GraphNode>) ci.Invoke (cps);
-        }
-        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
-        {
-            return (System.Collections.IEnumerator) ci.Invoke (cps);
-        }
-    }
-
-
-    /**
-     * @brief Steps through list of nodes that can possible be next in a flow-control sense.
-     */
-    public abstract class NNEnumeratorBase : System.Collections.Generic.IEnumerator<GraphNode> {
-        protected GraphNode nn;
-
-        public abstract bool MoveNext ();
-        public abstract void Reset ();
-
-        GraphNode System.Collections.Generic.IEnumerator<GraphNode>.Current {
-            get { return this.nn; }
-        }
-        object System.Collections.IEnumerator.Current {
-            get { return this.nn; }
-        }
-        void System.IDisposable.Dispose() { }
-    }
-
-
-    public class ScriptCollector : ScriptMyILGen {
-        public static readonly bool DEBUG = false;
-
-        public ScriptObjWriter wrapped;
-        public GraphNode firstLin, lastLin;
-        private bool resolvedSomething;
-        private int resolveSequence;
-        private int excBlkSeqNos;
-        public StackDepth stackDepth = new StackDepth ();
-
-        public GraphNodeBeginExceptionBlock curTryBlock = null;  // pushed at beginning of try
-                                                                 // popped at BEGINNING of catch/finally
-        public GraphNodeBeginExceptionBlock curExcBlock = null;  // pushed at beginning of try
-                                                                 // popped at END of catch/finally
-
-        private List<ScriptMyLocal> declaredLocals = new List<ScriptMyLocal> ();
-        private List<ScriptMyLabel> definedLabels  = new List<ScriptMyLabel> ();
-
-        public string methName { get { return wrapped.methName; } }
-
-        /**
-         * @brief Wrap the optimizer around the ScriptObjWriter to collect the instruction stream.
-         *        All stream-writing calls get saved to our graph nodes instead of being written to object file.
-         */
-        public ScriptCollector (ScriptObjWriter wrapped)
-        {
-            this.wrapped       = wrapped;
-            GraphNodeBegin gnb = new GraphNodeBegin (this);
-            this.firstLin      = gnb;
-            this.lastLin       = gnb;
-        }
-
-        public ScriptMyLocal DeclareLocal (Type type, string name)
-        {
-            ScriptMyLocal loc = new ScriptMyLocal ();
-            loc.name   = name;
-            loc.type   = type;
-            loc.number = wrapped.localNumber ++;
-            declaredLocals.Add (loc);
-            return loc;
-        }
-
-        public ScriptMyLabel DefineLabel (string name)
-        {
-            ScriptMyLabel lbl = new ScriptMyLabel ();
-            lbl.name   = name;
-            lbl.number = wrapped.labelNumber ++;
-            definedLabels.Add (lbl);
-            return lbl;
-        }
-
-        public void BeginExceptionBlock ()
-        {
-            GraphNodeBeginExceptionBlock tryBlock = new GraphNodeBeginExceptionBlock (this);
-            tryBlock.ChainLin ();
-            tryBlock.excBlkSeqNo = ++ this.excBlkSeqNos;
-            this.curExcBlock = tryBlock;
-            this.curTryBlock = tryBlock;
-        }
-
-        public void BeginCatchBlock (Type excType)
-        {
-            GraphNodeBeginCatchBlock catchBlock = new GraphNodeBeginCatchBlock (this, excType);
-            catchBlock.ChainLin ();
-            if (curExcBlock.catchFinallyBlock != null) throw new Exception ("only one catch/finally allowed per try");
-            curExcBlock.catchFinallyBlock = catchBlock;
-            curTryBlock = curExcBlock.tryBlock;
-        }
-
-        public void BeginFinallyBlock ()
-        {
-            GraphNodeBeginFinallyBlock finallyBlock = new GraphNodeBeginFinallyBlock (this);
-            finallyBlock.ChainLin ();
-            if (curExcBlock.catchFinallyBlock != null) throw new Exception ("only one catch/finally allowed per try");
-            curExcBlock.catchFinallyBlock = finallyBlock;
-            curTryBlock = curExcBlock.tryBlock;
-        }
-
-        public void EndExceptionBlock ()
-        {
-            GraphNodeEndExceptionBlock endExcBlock = new GraphNodeEndExceptionBlock (this);
-            endExcBlock.ChainLin ();
-            curExcBlock.endExcBlock = endExcBlock;
-            curTryBlock = curExcBlock.tryBlock;
-            curExcBlock = curExcBlock.excBlock;
-        }
-
-        public void Emit (Token errorAt, OpCode opcode)
-        {
-            if (opcode == OpCodes.Endfinally) {
-                new GraphNodeEmitNullEndfinally (this, errorAt).ChainLin ();
-            } else {
-                new GraphNodeEmitNull (this, errorAt, opcode).ChainLin ();
-            }
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, FieldInfo field)
-        {
-            if (field == null) throw new ArgumentNullException ("field");
-            new GraphNodeEmitField (this, errorAt, opcode, field).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
-        {
-            new GraphNodeEmitLocal (this, errorAt, opcode, myLocal).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, Type type)
-        {
-            new GraphNodeEmitType (this, errorAt, opcode, type).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
-        {
-            if (opcode == OpCodes.Leave) {
-                new GraphNodeEmitLabelLeave (this, errorAt, myLabel).ChainLin ();
-            } else {
-                new GraphNodeEmitLabel (this, errorAt, opcode, myLabel).ChainLin ();
-            }
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
-        {
-            new GraphNodeEmitLabels (this, errorAt, opcode, myLabels).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method)
-        {
-            if (method == null) throw new ArgumentNullException ("method");
-            new GraphNodeEmitIntMeth (this, errorAt, opcode, method).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, MethodInfo method)
-        {
-            if (method == null) throw new ArgumentNullException ("method");
-            new GraphNodeEmitExtMeth (this, errorAt, opcode, method).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor)
-        {
-            if (ctor == null) throw new ArgumentNullException ("ctor");
-            new GraphNodeEmitCtor (this, errorAt, opcode, ctor).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, double value)
-        {
-            new GraphNodeEmitDouble (this, errorAt, opcode, value).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, float value)
-        {
-            new GraphNodeEmitFloat (this, errorAt, opcode, value).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, int value)
-        {
-            new GraphNodeEmitInt (this, errorAt, opcode, value).ChainLin ();
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, string value)
-        {
-            new GraphNodeEmitString (this, errorAt, opcode, value).ChainLin ();
-        }
-
-        public void MarkLabel (ScriptMyLabel myLabel)
-        {
-            myLabel.whereAmI = new GraphNodeMarkLabel (this, myLabel);
-            myLabel.whereAmI.ChainLin ();
-        }
-
-        /**
-         * @brief Write the whole graph out to the object file.
-         */
-        public ScriptMyILGen WriteOutAll ()
-        {
-            foreach (ScriptMyLocal loc in declaredLocals) {
-                if (loc.isReferenced) wrapped.DeclareLocal (loc);
-            }
-            foreach (ScriptMyLabel lbl in definedLabels) {
-                wrapped.DefineLabel (lbl);
-            }
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                gn.WriteOutOne (wrapped);
-            }
-            return wrapped;
-        }
-
-        /**
-         * @brief Perform optimizations.
-         */
-        public void Optimize ()
-        {
-            if (curExcBlock != null) throw new Exception ("exception block still open");
-
-            /*
-             * If an instruction says it doesn't fall through, remove all instructions to
-             * the end of the block.
-             */
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                if (!gn.CanFallThrough ()) {
-                    GraphNode nn;
-                    while (((nn = gn.nextLin) != null) && !(nn is GraphNodeBlock) && 
-                                              !(nn is GraphNodeEndExceptionBlock)) {
-                        if ((gn.nextLin = nn.nextLin) != null) {
-                            nn.nextLin.prevLin = gn;
-                        }
-                    }
-                }
-            }
-
-            /*
-             * Scan for OpCodes.Leave instructions.
-             * For each found, its target for flow analysis purposes is the beginning of the corresponding
-             * finally block.  And the end of the finally block gets a conditional branch target of the 
-             * leave instruction's target.  A leave instruction can unwind zero or more finally blocks.
-             */
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                if (gn is GraphNodeEmitLabelLeave) {
-                    GraphNodeEmitLabelLeave leaveInstr = (GraphNodeEmitLabelLeave)gn;         // the leave instruction
-                    GraphNodeMarkLabel leaveTarget = leaveInstr.myLabel.whereAmI;             // label being targeted by leave
-                    GraphNodeBeginExceptionBlock leaveTargetsTryBlock =                       // try block directly enclosing leave target
-                        (leaveTarget == null) ? null : leaveTarget.tryBlock;              // ...it must not be unwound
-
-                    /*
-                     * Step through try { }s from the leave instruction towards its target looking for try { }s with finally { }s.
-                     * The leave instruction unconditionally branches to the beginning of the innermost one found.
-                     * The end of the last one found conditionally branches to the leave instruction's target.
-                     * If none found, the leave is a simple unconditional branch to its target.
-                     */
-                    GraphNodeBeginFinallyBlock innerFinallyBlock = null;
-                    for (GraphNodeBeginExceptionBlock tryBlock = leaveInstr.tryBlock;
-                         tryBlock != leaveTargetsTryBlock;
-                         tryBlock  = tryBlock.tryBlock) {
-                        if (tryBlock == null) throw new Exception ("leave target not at or outer to leave instruction");
-                        GraphNodeCatchFinallyBlock cfb = tryBlock.catchFinallyBlock;
-                        if (cfb is GraphNodeBeginFinallyBlock) {
-                            if (innerFinallyBlock == null) {
-                                leaveInstr.unwindTo = cfb;
-                            }
-                            innerFinallyBlock = (GraphNodeBeginFinallyBlock)cfb;
-                        }
-                    }
-
-                    /*
-                     * The end of the outermost finally being unwound can conditionally jump to the target of the leave instruction.
-                     * In the case of no finallies being unwound, the leave is just a simple unconditional branch.
-                     */
-                    if (innerFinallyBlock == null) {
-                        leaveInstr.unwindTo = leaveTarget;
-                    } else if (!innerFinallyBlock.leaveTargets.Contains (leaveTarget)) {
-                        innerFinallyBlock.leaveTargets.Add (leaveTarget);
-                    }
-                }
-            }
-
-            /*
-             * See which variables a particular block reads before writing.
-             * This just considers the block itself and nothing that it branches to or fallsthru to.
-             */
-            GraphNodeBlock currentBlock = null;
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                if (gn is GraphNodeBlock) currentBlock = (GraphNodeBlock)gn;
-                ScriptMyLocal rdlcl = gn.ReadsLocal ();
-                if ((rdlcl != null) &&
-                    !currentBlock.localsWrittenBeforeRead.Contains (rdlcl) && 
-                    !currentBlock.localsReadBeforeWritten.Contains (rdlcl)) {
-                    currentBlock.localsReadBeforeWritten.Add (rdlcl);
-                }
-                ScriptMyLocal wrlcl = gn.WritesLocal ();
-                if ((wrlcl != null) &&
-                    !currentBlock.localsWrittenBeforeRead.Contains (wrlcl) && 
-                    !currentBlock.localsReadBeforeWritten.Contains (wrlcl)) {
-                    currentBlock.localsWrittenBeforeRead.Add (wrlcl);
-                }
-            }
-
-            /*
-             * For every block we branch to, add that blocks readables to our list of readables,
-             * because we need to have those values valid on entry to our block.  But if we write the 
-             * variable before we can possibly branch to that block, then we don't need to have it valid 
-             * on entry to our block.  So basically it looks like the branch instruction is reading 
-             * everything required by any blocks it can branch to.
-             */
-            do {
-                this.resolvedSomething = false;
-                this.resolveSequence ++;
-                this.ResolveBlock ((GraphNodeBlock)firstLin);
-            } while (this.resolvedSomething);
-
-            /*
-             * Repeat the cutting loops as long as we keep finding stuff.
-             */
-            bool didSomething;
-            do {
-                didSomething = false;
-
-                /*
-                 * Strip out ldc.i4.1/xor/ldc.i4.1/xor
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if (!(gn is GraphNodeEmit)) continue;
-                    GraphNodeEmit xor2 = (GraphNodeEmit)gn;
-                    if (xor2.opcode != OpCodes.Xor) continue;
-                    if (!(xor2.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit ld12 = (GraphNodeEmit)xor2.prevLin;
-                    if (ld12.opcode != OpCodes.Ldc_I4_1) continue;
-                    if (!(ld12.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit xor1 = (GraphNodeEmit)ld12.prevLin;
-                    if (xor1.opcode != OpCodes.Xor) continue;
-                    if (!(xor2.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit ld11 = (GraphNodeEmit)xor1.prevLin;
-                    if (ld11.opcode != OpCodes.Ldc_I4_1) continue;
-                    ld11.prevLin.nextLin = xor2.nextLin;
-                    xor2.nextLin.prevLin = ld11.prevLin;
-                    didSomething = true;
-                }
-
-                /*
-                 * Replace c{cond}/ldc.i4.1/xor/br{false,true} -> c{cond}/br{true,false}
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if (!(gn is GraphNodeEmit)) continue;
-                    GraphNodeEmit brft = (GraphNodeEmit)gn;
-                    if ((brft.opcode != OpCodes.Brfalse) && (brft.opcode != OpCodes.Brtrue)) continue;
-                    if (!(brft.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit xor = (GraphNodeEmit)brft.prevLin;
-                    if (xor.opcode != OpCodes.Xor) continue;
-                    if (!(xor.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit ldc = (GraphNodeEmit)xor.prevLin;
-                    if (ldc.opcode != OpCodes.Ldc_I4_1) continue;
-                    if (!(ldc.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit cmp = (GraphNodeEmit)ldc.prevLin;
-                    if (cmp.opcode.StackBehaviourPop  != StackBehaviour.Pop1_pop1) continue;
-                    if (cmp.opcode.StackBehaviourPush != StackBehaviour.Pushi) continue;
-                    cmp.nextLin  = brft;
-                    brft.prevLin = cmp;
-                    brft.opcode  = (brft.opcode == OpCodes.Brfalse) ? OpCodes.Brtrue : OpCodes.Brfalse;
-                    didSomething = true;
-                }
-
-                /*
-                 * Replace c{cond}/br{false,true} -> b{!,}{cond}
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if (!(gn is GraphNodeEmit)) continue;
-                    GraphNodeEmit brft = (GraphNodeEmit)gn;
-                    if ((brft.opcode != OpCodes.Brfalse) && (brft.opcode != OpCodes.Brtrue)) continue;
-                    if (!(brft.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit cmp = (GraphNodeEmit)brft.prevLin;
-                    if (cmp.opcode.StackBehaviourPop  != StackBehaviour.Pop1_pop1) continue;
-                    if (cmp.opcode.StackBehaviourPush != StackBehaviour.Pushi) continue;
-                    cmp.prevLin.nextLin = brft;
-                    brft.prevLin = cmp.prevLin;
-                    bool brtru = (brft.opcode == OpCodes.Brtrue);
-                         if (cmp.opcode == OpCodes.Ceq)    brft.opcode = brtru ? OpCodes.Beq    : OpCodes.Bne_Un;
-                    else if (cmp.opcode == OpCodes.Cgt)    brft.opcode = brtru ? OpCodes.Bgt    : OpCodes.Ble;
-                    else if (cmp.opcode == OpCodes.Cgt_Un) brft.opcode = brtru ? OpCodes.Bgt_Un : OpCodes.Ble_Un;
-                    else if (cmp.opcode == OpCodes.Clt)    brft.opcode = brtru ? OpCodes.Blt    : OpCodes.Bge;
-                    else if (cmp.opcode == OpCodes.Clt_Un) brft.opcode = brtru ? OpCodes.Blt_Un : OpCodes.Bge_Un;
-                    else throw new Exception ();
-                    didSomething = true;
-                }
-
-                /*
-                 * Replace ld{c.i4.0,null}/br{ne.un,eq} -> br{true,false}
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if (!(gn is GraphNodeEmit)) continue;
-                    GraphNodeEmit brcc = (GraphNodeEmit)gn;
-                    if ((brcc.opcode != OpCodes.Bne_Un) && (brcc.opcode != OpCodes.Beq)) continue;
-                    if (!(brcc.prevLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit ldc0 = (GraphNodeEmit)brcc.prevLin;
-                    if ((ldc0.opcode != OpCodes.Ldc_I4_0) && (ldc0.opcode != OpCodes.Ldnull)) continue;
-                    ldc0.prevLin.nextLin = brcc;
-                    brcc.prevLin = ldc0.prevLin;
-                    brcc.opcode  = (brcc.opcode == OpCodes.Bne_Un) ? OpCodes.Brtrue : OpCodes.Brfalse;
-                    didSomething = true;
-                }
-
-                /*
-                 * Replace:
-                 *    ldloc v1
-                 *    stloc v2
-                 *    ld<anything> except ld<anything> v2
-                 *    ldloc v2
-                 *      ...v2 unreferenced hereafter
-                 * With:
-                 *    ld<anything> except ld<anything> v2
-                 *    ldloc v1
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-
-                    // check for 'ldloc v1' instruction
-                    if (!(gn is GraphNodeEmitLocal)) continue;
-                    GraphNodeEmitLocal ldlv1 = (GraphNodeEmitLocal)gn;
-                    if (ldlv1.opcode != OpCodes.Ldloc) continue;
-
-                    // check for 'stloc v2' instruction
-                    if (!(ldlv1.nextLin is GraphNodeEmitLocal)) continue;
-                    GraphNodeEmitLocal stlv2 = (GraphNodeEmitLocal)ldlv1.nextLin;
-                    if (stlv2.opcode != OpCodes.Stloc) continue;
-
-                    // check for 'ld<anything> except ld<anything> v2' instruction
-                    if (!(stlv2.nextLin is GraphNodeEmit)) continue;
-                    GraphNodeEmit ldany = (GraphNodeEmit)stlv2.nextLin;
-                    if (!ldany.opcode.ToString ().StartsWith ("ld")) continue;
-                    if ((ldany is GraphNodeEmitLocal) &&
-                        ((GraphNodeEmitLocal)ldany).myLocal == stlv2.myLocal) continue;
-
-                    // check for 'ldloc v2' instruction
-                    if (!(ldany.nextLin is GraphNodeEmitLocal)) continue;
-                    GraphNodeEmitLocal ldlv2 = (GraphNodeEmitLocal)ldany.nextLin;
-                    if (ldlv2.opcode != OpCodes.Ldloc) continue;
-                    if (ldlv2.myLocal != stlv2.myLocal) continue;
-
-                    // check that v2 is not needed after this at all
-                    if (IsLocalNeededAfterThis (ldlv2, ldlv2.myLocal)) continue;
-
-                    // make 'ld<anything>...' the first instruction
-                    ldany.prevLin = ldlv1.prevLin;
-                    ldany.prevLin.nextLin = ldany;
-
-                    // make 'ldloc v1' the second instruction
-                    ldany.nextLin = ldlv1;
-                    ldlv1.prevLin = ldany;
-
-                    // and make 'ldloc v1' the last instruction
-                    ldlv1.nextLin = ldlv2.nextLin;
-                    ldlv1.nextLin.prevLin = ldlv1;
-
-                    didSomething = true;
-                }
-
-                /*
-                 * Remove all the stloc/ldloc that are back-to-back without the local
-                 * being needed afterwards.  If it is needed afterwards, replace the 
-                 * stloc/ldloc with dup/stloc.
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if ((gn is GraphNodeEmitLocal) && 
-                        (gn.prevLin is GraphNodeEmitLocal)) {
-                        GraphNodeEmitLocal stloc = (GraphNodeEmitLocal)gn.prevLin;
-                        GraphNodeEmitLocal ldloc = (GraphNodeEmitLocal)gn;
-                        if ((stloc.opcode  == OpCodes.Stloc) && 
-                            (ldloc.opcode  == OpCodes.Ldloc) && 
-                            (stloc.myLocal == ldloc.myLocal)) {
-                            if (IsLocalNeededAfterThis (ldloc, ldloc.myLocal)) {
-                                GraphNodeEmitNull dup = new GraphNodeEmitNull (this, stloc.errorAt, OpCodes.Dup);
-                                dup.nextLin   = stloc;
-                                dup.prevLin   = stloc.prevLin;
-                                stloc.nextLin = ldloc.nextLin;
-                                stloc.prevLin = dup;
-                                dup.prevLin.nextLin   = dup;
-                                stloc.nextLin.prevLin = stloc;
-                                gn = stloc;
-                            } else {
-                                stloc.prevLin.nextLin = ldloc.nextLin;
-                                ldloc.nextLin.prevLin = stloc.prevLin;
-                                gn = stloc.prevLin;
-                            }
-                            didSomething = true;
-                        }
-                    }
-                }
-
-                /*
-                 * Remove all write-only local variables, ie, those with no ldloc[a] references.
-                 * Replace any stloc instructions with pops.
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    ScriptMyLocal rdlcl = gn.ReadsLocal ();
-                    if (rdlcl != null) rdlcl.isReferenced = true;
-                }
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    ScriptMyLocal wrlcl = gn.WritesLocal ();
-                    if ((wrlcl != null) && !wrlcl.isReferenced) {
-                        if (!(gn is GraphNodeEmitLocal) || (((GraphNodeEmitLocal)gn).opcode != OpCodes.Stloc)) {
-                            throw new Exception ("expecting stloc");
-                        }
-                        GraphNodeEmitNull pop = new GraphNodeEmitNull (this, ((GraphNodeEmit)gn).errorAt, OpCodes.Pop);
-                        pop.nextLin = gn.nextLin;
-                        pop.prevLin = gn.prevLin;
-                        gn.nextLin.prevLin = pop;
-                        gn.prevLin.nextLin = pop;
-                        gn = pop;
-                        didSomething = true;
-                    }
-                }
-
-                /*
-                 * Remove any Ld<const>/Dup,Pop.
-                 */
-                for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                    if ((gn is GraphNodeEmit) && 
-                        (gn.nextLin is GraphNodeEmit)) {
-                        GraphNodeEmit gne = (GraphNodeEmit)gn;
-                        GraphNodeEmit nne = (GraphNodeEmit)gn.nextLin;
-                        if (gne.isPoppable && (nne.opcode == OpCodes.Pop)) {
-                            gne.prevLin.nextLin = nne.nextLin;
-                            nne.nextLin.prevLin = gne.prevLin;
-                            gn = gne.prevLin;
-                            didSomething = true;
-                        }
-                    }
-                }
-            } while (didSomething);
-
-            /*
-             * Dump out the results.
-             */
-            if (DEBUG) {
-                Console.WriteLine ("");
-                Console.WriteLine (methName);
-                Console.WriteLine ("  resolveSequence=" + this.resolveSequence);
-
-                Console.WriteLine ("  Locals:");
-                foreach (ScriptMyLocal loc in declaredLocals) {
-                    Console.WriteLine ("    " + loc.type.Name + "  " + loc.name);
-                }
-
-                Console.WriteLine ("  Labels:");
-                foreach (ScriptMyLabel lbl in definedLabels) {
-                    Console.WriteLine ("    " + lbl.name);
-                }
-
-                Console.WriteLine ("  Code:");
-                DumpCode ();
-            }
-        }
-
-        private void DumpCode ()
-        {
-            int linSeqNos = 0;
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                gn.linSeqNo = ++ linSeqNos;
-            }
-            for (GraphNode gn = firstLin; gn != null; gn = gn.nextLin) {
-                StringBuilder sb = new StringBuilder ();
-                gn.DebStringExt (sb);
-                Console.WriteLine (sb.ToString ());
-                if (gn is GraphNodeBlock) {
-                    GraphNodeBlock gnb = (GraphNodeBlock)gn;
-                    foreach (ScriptMyLocal lcl in gnb.localsReadBeforeWritten) {
-                        Console.WriteLine ("         reads " + lcl.name);
-                    }
-                }
-            }
-        }
-
-        /**
-         * @brief Scan the given block for branches to other blocks.
-         *        For any locals read by those blocks, mark them as being read by this block, 
-         *        provided this block has not written them by that point.  This makes it look 
-         *        as though the branch instruction is reading all the locals needed by any 
-         *        target blocks.
-         */
-        private void ResolveBlock (GraphNodeBlock currentBlock)
-        {
-            if (currentBlock.hasBeenResolved == this.resolveSequence) return;
-
-            /*
-             * So we don't recurse forever on a backward branch.
-             */
-            currentBlock.hasBeenResolved = this.resolveSequence;
-
-            /*
-             * Assume we haven't written any locals yet.
-             */
-            List<ScriptMyLocal> localsWrittenSoFar = new List<ScriptMyLocal> ();
-
-            /*
-             * Scan through the instructions in this block.
-             */
-            for (GraphNode gn = currentBlock; gn != null;) {
-
-                /*
-                 * See if the instruction writes a local we don't know about yet.
-                 */
-                ScriptMyLocal wrlcl = gn.WritesLocal ();
-                if ((wrlcl != null) && !localsWrittenSoFar.Contains (wrlcl)) {
-                    localsWrittenSoFar.Add (wrlcl);
-                }
-
-                /*
-                 * Scan through all the possible next instructions after this.
-                 * Note that if we are in the first part of a try/catch/finally block, 
-                 * every instruction conditionally branches to the beginning of the 
-                 * second part (the catch/finally block).
-                 */
-                GraphNode nextFallthruNode = null;
-                foreach (GraphNode nn in gn.NextNodes) {
-                    if (nn is GraphNodeBlock) {
-
-                        /*
-                         * Start of a block, go through all locals needed by that block on entry.
-                         */
-                        GraphNodeBlock nextBlock = (GraphNodeBlock)nn;
-                        ResolveBlock (nextBlock);
-                        foreach (ScriptMyLocal readByNextBlock in nextBlock.localsReadBeforeWritten) {
-
-                            /*
-                             * If this block hasn't written it by now and this block doesn't already
-                             * require it on entry, say this block requires it on entry.
-                             */
-                            if (!localsWrittenSoFar.Contains (readByNextBlock) && 
-                                !currentBlock.localsReadBeforeWritten.Contains (readByNextBlock)) {
-                                currentBlock.localsReadBeforeWritten.Add (readByNextBlock);
-                                this.resolvedSomething = true;
-                            }
-                        }
-                    } else {
-
-                        /*
-                         * Not start of a block, should be normal fallthru instruction.
-                         */
-                        if (nextFallthruNode != null) throw new Exception ("more than one fallthru from " + gn.ToString ());
-                        nextFallthruNode = nn;
-                    }
-                }
-
-                /*
-                 * Process next instruction if it isn't the start of a block.
-                 */
-                if (nextFallthruNode == gn) throw new Exception ("can't fallthru to self");
-                gn = nextFallthruNode;
-            }
-        }
-
-        /**
-         * @brief Figure out whether the value in a local var is needed after the given instruction.
-         *        True if we reach the end of the program on all branches before reading it
-         *        True if we write the local var on all branches before reading it
-         *        False otherwise
-         */
-        private bool IsLocalNeededAfterThis (GraphNode node, ScriptMyLocal local)
-        {
-            do {
-                GraphNode nextFallthruNode = null;
-                foreach (GraphNode nn in node.NextNodes) {
-                    if (nn is GraphNodeBlock) {
-                        if (((GraphNodeBlock)nn).localsReadBeforeWritten.Contains (local)) {
-                            return true;
-                        }
-                    } else {
-                        nextFallthruNode = nn;
-                    }
-                }
-                node = nextFallthruNode;
-                if (node == null) return false;
-                if (node.ReadsLocal () == local) return true;
-            } while (node.WritesLocal () != local);
-            return false;
-        }
-
-        public static void PadToLength (StringBuilder sb, int len, string str)
-        {
-            int pad = len - sb.Length;
-            if (pad < 0) pad = 0;
-            sb.Append (str.PadLeft (pad));
-        }
-    }
-}

+ 0 - 1677
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs

@@ -1,1677 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * @brief Compute values used during code generation to keep track of where computed values are stored.
- *
- *        Conceptually holds the memory address and type of the value
- *        such as that used for a local variable, global variable, temporary variable.
- *        Also used for things like constants and function/method entrypoints,
- *        they are basically treated as read-only variables.
- *
- *            cv.type - type of the value
- *
- *            cv.PushVal() - pushes the value on the CIL stack
- *            cv.PushRef() - pushes address of the value on the CIL stack
- *
- *            cv.PopPre()  - gets ready to pop from the CIL stack
- *                           ...by possibly pushing something
- *                <push value to be popped>
- *            cv.PushPre() - pops value from the CIL stack
- *
- *        If the type is a TokenTypeSDTypeDelegate, the location is callable, 
- *        so you get these additional functions:
- *
- *            cv.GetRetType()  - gets function/method's return value type
- *                               TokenTypeVoid if void
- *                               null if not a delegate
- *            cv.GetArgTypes() - gets array of argument types
- *                               as seen by script level, ie, 
- *                               does not include any hidden 'this' type
- *            cv.GetArgSig()   - gets argument signature eg, "(integer,list)"
- *                               null if not a delegate
- *
- *            cv.CallPre()     - gets ready to call the function/method
- *                               ...by possibly pushing something
- *                                  such as a 'this' pointer
- *                <push call args left-to-right>
- *            cv.CallPost()    - calls the function/method
- */
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-
-    /**
-     * @brief Location of a value
-     *        Includes constants, expressions and temp variables.
-     */
-    public abstract class CompValu {
-        protected static readonly MethodInfo gsmdMethodInfo = 
-                typeof (XMRInstAbstract).GetMethod ("GetScriptMethodDelegate", 
-                                                    new Type[] { typeof (string), typeof (string), typeof (object) });
-
-        private static readonly MethodInfo avpmListMethInfo   = typeof (XMRInstArrays).GetMethod ("PopList",   new Type[] { typeof (int), typeof (LSL_List) });
-        private static readonly MethodInfo avpmObjectMethInfo = typeof (XMRInstArrays).GetMethod ("PopObject", new Type[] { typeof (int), typeof (object) });
-        private static readonly MethodInfo avpmStringMethInfo = typeof (XMRInstArrays).GetMethod ("PopString", new Type[] { typeof (int), typeof (string) });
-
-        public TokenType type;        // type of the value and where in the source it was used
-
-        public CompValu (TokenType type)
-        {
-            this.type = type;
-        }
-
-        public Type ToSysType()
-        {
-            return (type.ToLSLWrapType () != null) ? type.ToLSLWrapType () : type.ToSysType ();
-        }
-
-        // if a field of an XMRInstArrays array cannot be directly written,
-        // get the method that can write it
-        private static MethodInfo ArrVarPopMeth (FieldInfo fi)
-        {
-            if (fi.Name == "iarLists")   return avpmListMethInfo;
-            if (fi.Name == "iarObjects") return avpmObjectMethInfo;
-            if (fi.Name == "iarStrings") return avpmStringMethInfo;
-            return null;
-        }
-
-        // emit code to push value onto stack
-        public void PushVal (ScriptCodeGen scg, Token errorAt, TokenType stackType)
-        {
-            this.PushVal (scg, errorAt, stackType, false);
-        }
-        public void PushVal (ScriptCodeGen scg, Token errorAt, TokenType stackType, bool explicitAllowed)
-        {
-            this.PushVal (scg, errorAt);
-            TypeCast.CastTopOfStack (scg, errorAt, this.type, stackType, explicitAllowed);
-        }
-        public abstract void PushVal (ScriptCodeGen scg, Token errorAt);
-        public abstract void PushRef (ScriptCodeGen scg, Token errorAt);
-
-        // emit code to pop value from stack
-        public void PopPost (ScriptCodeGen scg, Token errorAt, TokenType stackType)
-        {
-            TypeCast.CastTopOfStack (scg, errorAt, stackType, this.type, false);
-            this.PopPost (scg, errorAt);
-        }
-        public virtual void PopPre (ScriptCodeGen scg, Token errorAt) { }  // call this before pushing value to be popped
-        public abstract void PopPost (ScriptCodeGen scg, Token errorAt);   // call this after pushing value to be popped
-
-        // return true: doing a PushVal() does not involve CheckRun()
-        //       false: otherwise
-        public virtual bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return true;
-        }
-
-        /*
-         * These additional functions are available if the type is a delegate
-         */
-        public TokenType GetRetType ()
-        {
-            if (!(type is TokenTypeSDTypeDelegate)) return null;
-            return ((TokenTypeSDTypeDelegate)type).decl.GetRetType ();
-        }
-        public TokenType[] GetArgTypes ()
-        {
-            if (!(type is TokenTypeSDTypeDelegate)) return null;
-            return ((TokenTypeSDTypeDelegate)type).decl.GetArgTypes ();
-        }
-        public string GetArgSig ()
-        {
-            if (!(type is TokenTypeSDTypeDelegate)) return null;
-            return ((TokenTypeSDTypeDelegate)type).decl.GetArgSig ();
-        }
-
-        // These are used only if type is a delegate too
-        // - but it is a real delegate pointer in a global or local variable or a field, etc
-        //   ie, PushVal() pushes a delegate pointer
-        // - so we must have CallPre() push the delegate pointer as a 'this' for this.Invoke(...)
-        // - and CallPost() call the delegate's Invoke() method
-        // - we assume the target function is non-trivial so we always use a call label
-        public virtual void CallPre (ScriptCodeGen scg, Token errorAt)   // call this before pushing arguments
-        {
-            new ScriptCodeGen.CallLabel (scg, errorAt);
-            this.PushVal (scg, errorAt);
-        }
-        public virtual void CallPost (ScriptCodeGen scg, Token errorAt)  // call this after pushing arguments
-        {
-            TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
-            MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo ();
-            scg.ilGen.Emit (errorAt, OpCodes.Callvirt, invokeMethodInfo);
-            scg.openCallLabel = null;
-        }
-
-        /*
-         * Utilities used by CompValuGlobalVar and CompValuInstField
-         * where the value is located in a type-dependent array.
-         */
-        protected void EmitFieldPushVal (ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldfld, var.vTableArray);   // which array
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, var.vTableIndex);  // which array element
-            if (type is TokenTypeFloat) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem_R8);
-            } else if (type is TokenTypeInt) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem_I4);
-            } else if (type is TokenTypeSDTypeDelegate) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (object));
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, ToSysType ());
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, ToSysType ());
-            }
-        }
-
-        protected void EmitFieldPushRef (ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
-        {
-            if (ArrVarPopMeth (var.vTableArray) != null) {
-                scg.ErrorMsg (errorAt, "can't take address of this variable");
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Ldfld, var.vTableArray);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, var.vTableIndex);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldelema, ToSysType());
-        }
-
-        protected void EmitFieldPopPre (ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
-        {
-            if (ArrVarPopMeth (var.vTableArray) != null) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, var.vTableIndex);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, var.vTableArray);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, var.vTableIndex);
-            }
-        }
-
-        protected void EmitFieldPopPost (ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
-        {
-            if (ArrVarPopMeth (var.vTableArray) != null) {
-                scg.ilGen.Emit (errorAt, OpCodes.Call, ArrVarPopMeth (var.vTableArray));
-            } else if (type is TokenTypeFloat) {
-                scg.ilGen.Emit (errorAt, OpCodes.Stelem_R8);
-            } else if (type is TokenTypeInt) {
-                scg.ilGen.Emit (errorAt, OpCodes.Stelem_I4);
-            } else if (type is TokenTypeSDTypeDelegate) {
-                scg.ilGen.Emit (errorAt, OpCodes.Stelem, typeof (object));
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Stelem, ToSysType ());
-            }
-        }
-
-        /**
-         * @brief With value pushed on stack, emit code to set a property by calling its setter() method.
-         * @param scg = which script is being compiled
-         * @param errorAt = for error messages
-         * @param type = property type
-         * @param setProp = setter() method
-         */
-        protected void EmitPopPostProp (ScriptCodeGen scg, Token errorAt, TokenType type, CompValu setProp)
-        {
-            ScriptMyLocal temp = scg.ilGen.DeclareLocal (type.ToSysType (), "__spr_" + errorAt.Unique);
-            scg.ilGen.Emit   (errorAt, OpCodes.Stloc, temp);
-            setProp.CallPre  (scg, errorAt);
-            scg.ilGen.Emit   (errorAt, OpCodes.Ldloc, temp);
-            setProp.CallPost (scg, errorAt);
-        }
-    }
-
-    // The value is kept in an (XMR_Array) array element
-    public class CompValuArEle : CompValu {
-        public  CompValu arr;
-        private CompValu idx;
-        private TokenTypeObject tto;
-
-        private static readonly MethodInfo getByKeyMethodInfo = typeof (XMR_Array).GetMethod ("GetByKey", 
-                                                                                              new Type[] { typeof (object) });
-        private static readonly MethodInfo setByKeyMethodInfo = typeof (XMR_Array).GetMethod ("SetByKey", 
-                                                                                              new Type[] { typeof (object),
-                                                                                                           typeof (object) });
-
-        // type = TokenTypeObject always, as our array elements are always of type 'object'
-        // arr  = where the array object itself is stored
-        // idx  = where the index value is stored
-        public CompValuArEle (TokenType type, CompValu arr, CompValu idx) : base (type)
-        {
-            this.arr = arr;
-            this.idx = idx;
-            this.tto = new TokenTypeObject (this.type);
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            arr.PushVal (scg, errorAt);   // array
-            idx.PushVal (scg, errorAt, this.tto);  // key
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getByKeyMethodInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "array element not allowed here");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            arr.PushVal (scg, errorAt);            // array
-            idx.PushVal (scg, errorAt, this.tto);  // key
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, setByKeyMethodInfo);
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading an
-        // XMR_Array element is trivial
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // The value is kept in the current function's argument list
-    public class CompValuArg : CompValu {
-        public int index;
-        public bool readOnly;
-
-        private static OpCode[] ldargs = { OpCodes.Ldarg_0, OpCodes.Ldarg_1, 
-                                           OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
-
-        public CompValuArg (TokenType type, int index) : base (type)
-        {
-            this.index = index;
-        }
-        public CompValuArg (TokenType type, int index, bool ro) : base (type)
-        {
-            this.index = index;
-            this.readOnly = ro;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-                 if (index < ldargs.Length) scg.ilGen.Emit (errorAt, ldargs[index]);
-            else if (index <= 255) scg.ilGen.Emit (errorAt, OpCodes.Ldarg_S, index);
-                                else scg.ilGen.Emit (errorAt, OpCodes.Ldarg, index);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if (readOnly) {
-                scg.ErrorMsg (errorAt, "location cannot be written to");
-            }
-            if (index <= 255) scg.ilGen.Emit (errorAt, OpCodes.Ldarga_S, index);
-                           else scg.ilGen.Emit (errorAt, OpCodes.Ldarga, index);
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (readOnly) {
-                scg.ErrorMsg (errorAt, "location cannot be written to");
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Starg, index);
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading an
-        // argument is trivial
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // The value is a character constant
-    public class CompValuChar : CompValu {
-        public char x;
-
-        public CompValuChar (TokenType type, char x) : base (type)
-        {
-            if (!(this.type is TokenTypeChar)) {
-                this.type = new TokenTypeChar (this.type);
-            }
-            this.x = x;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, (int)x);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into contant");
-        }
-    }
-
-    // The value is kept in a struct/class field of an internal struct/class
-    public class CompValuField : CompValu {
-        CompValu obj;
-        FieldInfo field;
-
-        public CompValuField (TokenType type, CompValu obj, FieldInfo field) : base (type)
-        {
-            this.obj   = obj;
-            this.field = field;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if (field.ReflectedType.IsValueType) {
-                obj.PushRef (scg, errorAt);
-            } else {
-                obj.PushVal (scg, errorAt);
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Ldfld, field);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if (field.ReflectedType.IsValueType) {
-                obj.PushRef (scg, errorAt);
-            } else {
-                obj.PushVal (scg, errorAt);
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Ldflda, field);
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (field.ReflectedType.IsValueType) {
-                obj.PushRef (scg, errorAt);
-            } else {
-                obj.PushVal (scg, errorAt);
-            }
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Stfld, field);
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading an
-        // field of a class/struct is trivial
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // Accessing an element of a fixed-dimension array
-    public class CompValuFixArEl : CompValu {
-        private CompValu   baseRVal;
-        private CompValu[] subRVals;
-
-        private int nSubs;
-        private TokenDeclVar getFunc;
-        private TokenDeclVar setFunc;
-        private TokenTypeInt tokenTypeInt;
-
-        /**
-         * @brief Set up to access an element of an array.
-         * @param scg = what script we are compiling
-         * @param baseRVal = what array we are accessing
-         * @param subRVals = the subscripts being applied
-         */
-        public CompValuFixArEl (ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals) : base (GetElementType (scg, baseRVal, subRVals))
-        {
-            this.baseRVal = baseRVal;  // location of the array itself
-            this.subRVals = subRVals;  // subscript values
-            this.nSubs    = subRVals.Length;
-
-            TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
-            TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-            tokenTypeInt = new TokenTypeInt (sdtType);
-
-            TokenName name = new TokenName (sdtType, "Get");
-            TokenType[] argsig = new TokenType[nSubs];
-            for (int i = 0; i < nSubs; i ++) {
-                argsig[i] = tokenTypeInt;
-            }
-            getFunc = scg.FindThisMember (sdtDecl, name, argsig);
-
-            name = new TokenName (sdtType, "Set");
-            argsig = new TokenType[nSubs+1];
-            for (int i = 0; i < nSubs; i ++) {
-                argsig[i] = tokenTypeInt;
-            }
-            argsig[nSubs] = getFunc.retType;
-            setFunc = scg.FindThisMember (sdtDecl, name, argsig);
-        }
-
-        /**
-         * @brief Read array element and push value on stack.
-         */
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            // call script-defined class' Get() method to fetch the value
-            baseRVal.PushVal (scg, errorAt);
-            for (int i = 0; i < nSubs; i ++) {
-                subRVals[i].PushVal (scg, errorAt, tokenTypeInt);
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getFunc.ilGen);
-        }
-
-        /**
-         * @brief Push address of array element on stack.
-         */
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("tu stOOpid to get array element address");
-        }
-
-        /**
-         * @brief Prepare to write array element.
-         */
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            // set up call to script-defined class' Set() method to write the value
-            baseRVal.PushVal (scg, errorAt);
-            for (int i = 0; i < nSubs; i ++) {
-                subRVals[i].PushVal (scg, errorAt, tokenTypeInt);
-            }
-        }
-
-        /**
-         * @brief Pop value from stack and write array element.
-         */
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            // call script-defined class' Set() method to write the value
-            scg.ilGen.Emit (errorAt, OpCodes.Call, setFunc.ilGen);
-        }
-
-        /**
-         * @brief Get the array element type by getting the Get() functions return type.
-         *        Crude but effective.
-         * @param scg = what script we are compiling
-         * @param baseRVal = what array we are accessing
-         * @param subRVals = the subscripts being applied
-         * @returns array element type
-         */
-        private static TokenType GetElementType (ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals)
-        {
-            TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
-            TokenDeclSDTypeClass sdtDecl = sdtType.decl;
-            TokenName name = new TokenName (sdtType, "Get");
-            int nSubs = subRVals.Length;
-            TokenType[] argsig = new TokenType[nSubs];
-            argsig[0] = new TokenTypeInt (sdtType);
-            for (int i = 0; ++ i < nSubs;) {
-                argsig[i] = argsig[0];
-            }
-            TokenDeclVar getFunc = scg.FindThisMember (sdtDecl, name, argsig);
-            return getFunc.retType;
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading an
-        // fixed-dimension array element is trivial
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // The value is a float constant
-    public class CompValuFloat : CompValu {
-        public double x;
-
-        public CompValuFloat (TokenType type, double x) : base (type)
-        {
-            if (!(this.type is TokenTypeFloat)) {
-                this.type = new TokenTypeFloat (this.type);
-            }
-            this.x = x;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, x);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into constant");
-        }
-    }
-
-    // The value is the entrypoint of a script-defined global function.
-    // These are also used for script-defined type static methods as the calling convention is the same,
-    // ie, the XMRInstance pointer is a hidden first argument.
-    // There is just one of these created when the function is being compiled as there is only one value
-    // of the function.
-    public class CompValuGlobalMeth : CompValu {
-        private TokenDeclVar func;
-
-        public CompValuGlobalMeth (TokenDeclVar declFunc) : base (declFunc.GetDelType ())
-        {
-            this.func = declFunc;
-        }
-
-        /**
-         * @brief PushVal for a function/method means push a delegate on the stack.
-         *        We build a call to the DynamicMethod's CreateDelegate() function 
-         *        to create the delegate.  Slip the scriptinstance pointer as the 
-         *        function's arg 0 so it will get passed to the function when called.
-         */
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            string dtn = type.ToString ();
-            if (dtn.StartsWith ("delegate ")) dtn = dtn.Substring (9);
-
-            // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
-            //   where methName = [<sdtclass>.]<methname>(<argtypes>)
-            //        signature = <rettype>(<argtypes>)
-            //             arg0 = scriptinstance (XMRInstance)
-            scg.PushXMRInst ();                                     // [0] scriptinstance
-            scg.ilGen.Emit (errorAt, OpCodes.Ldstr, func.ilGen.methName);    // [1] method name
-            scg.ilGen.Emit (errorAt, OpCodes.Ldstr, dtn);                    // [2] delegate type name
-            scg.PushXMRInst ();                                     // [3] scriptinstance
-            scg.ilGen.Emit (errorAt, OpCodes.Callvirt, gsmdMethodInfo);      // [0] delegate instance
-            scg.ilGen.Emit (errorAt, OpCodes.Castclass, type.ToSysType ());  // [0] cast to correct delegate class
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get ref to global method");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into global method");
-        }
-
-        /**
-         * @brief A direct call is much simpler than pushing a delegate.
-         *        Just push the XMRInstance pointer, push the args and finally call the function.
-         */
-        public override void CallPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (!this.func.IsFuncTrivial (scg)) new ScriptCodeGen.CallLabel (scg, errorAt);
-
-            // all script-defined global functions are static methods created by DynamicMethod()
-            // and the first argument is always the XMR_Instance pointer
-            scg.PushXMRInst ();
-        }
-        public override void CallPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, func.ilGen);
-            if (!this.func.IsFuncTrivial (scg)) scg.openCallLabel = null;
-        }
-    }
-
-    // The value is in a script-global variable = ScriptModule instance variable
-    // It could also be a script-global property
-    public class CompValuGlobalVar : CompValu {
-        private static readonly FieldInfo glblVarsFieldInfo = typeof (XMRInstAbstract).GetField ("glblVars");
-
-        private TokenDeclVar declVar;
-
-        public CompValuGlobalVar (TokenDeclVar declVar, XMRInstArSizes glblSizes) : base (declVar.type)
-        {
-            this.declVar = declVar;
-            if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                declVar.type.AssignVarSlot (declVar, glblSizes);
-            }
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                scg.PushXMRInst ();
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
-                EmitFieldPushVal (scg, errorAt, declVar);
-            } else if (declVar.getProp != null) {
-                declVar.getProp.location.CallPre  (scg, errorAt);
-                declVar.getProp.location.CallPost (scg, errorAt);
-            } else {
-                scg.ErrorMsg (errorAt, "property not readable");
-                scg.PushDefaultValue (declVar.type);
-            }
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                scg.PushXMRInst ();
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
-                EmitFieldPushRef (scg, errorAt, declVar);
-            } else {
-                scg.ErrorMsg (errorAt, "cannot get address of property");
-            }
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                scg.PushXMRInst ();
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
-                EmitFieldPopPre (scg, errorAt, declVar);
-            } else if (declVar.setProp == null) {
-                scg.ErrorMsg (errorAt, "property not writable");
-            }
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.getProp == null) && (declVar.setProp == null)) {
-                EmitFieldPopPost (scg, errorAt, declVar);
-            } else if (declVar.setProp != null) {
-                EmitPopPostProp (scg, errorAt, declVar.type, declVar.setProp.location);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Pop);
-            }
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading an
-        // global variable is trivial provided it is 
-        // not a property or the property function is
-        // trivial.
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l && ((declVar.getProp == null) || declVar.getProp.IsFuncTrivial (scg));
-        }
-    }
-
-    // The value is in an $idxprop property of a script-defined type class or interface instance.
-    // Reading and writing is via a method call.
-    public class CompValuIdxProp : CompValu {
-        private TokenDeclVar idxProp;  // $idxprop property within baseRVal
-        private CompValu baseRVal;     // pointer to class or interface object containing property
-        private TokenType[] argTypes;  // argument types as required by $idxprop declaration
-        private CompValu[] indices;    // actual index values to pass to getter/setter method
-        private CompValu setProp;      // location of setter method
-
-        public CompValuIdxProp (TokenDeclVar idxProp, CompValu baseRVal, TokenType[] argTypes, CompValu[] indices) : base (idxProp.type)
-        {           
-            this.idxProp  = idxProp;
-            this.baseRVal = baseRVal;
-            this.argTypes = argTypes;
-            this.indices  = indices;
-        }
-
-        /**
-         * @brief Pushing the property's value is a matter of calling the getter method
-         *        with the supplied argument list as is.
-         */
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if (idxProp.getProp != null) {
-                if (!idxProp.getProp.IsFuncTrivial (scg)) {
-                    for (int i = indices.Length; -- i >= 0;) {
-                        indices[i] = scg.Trivialize (indices[i], errorAt);
-                    }
-                }
-                CompValu getProp = GetIdxPropMeth (idxProp.getProp);
-                getProp.CallPre (scg, errorAt);
-                for (int i = 0; i < indices.Length; i ++) {
-                    indices[i].PushVal (scg, errorAt, argTypes[i]);
-                }
-                getProp.CallPost (scg, errorAt);
-            } else {
-                // write-only property
-                scg.ErrorMsg (errorAt, "member not readable");
-                scg.PushDefaultValue (idxProp.type);
-            }
-        }
-
-        /**
-         * @brief A property does not have a memory address.
-         */
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "member has no address");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-
-        /**
-         * @brief Preparing to write a property consists of preparing to call the setter method
-         *        then pushing the index arguments.
-         */
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (idxProp.setProp != null) {
-                if (!idxProp.setProp.IsFuncTrivial (scg)) {
-                    for (int i = indices.Length; -- i >= 0;) {
-                        indices[i] = scg.Trivialize (indices[i], errorAt);
-                    }
-                }
-                this.setProp = GetIdxPropMeth (idxProp.setProp);
-                this.setProp.CallPre (scg, errorAt);
-                for (int i = 0; i < indices.Length; i ++) {
-                    indices[i].PushVal (scg, errorAt, argTypes[i]);
-                }
-            } else {
-                // read-only property
-                scg.ErrorMsg (errorAt, "member not writable");
-            }
-        }
-
-        /**
-         * @brief Finishing writing a property consists of finishing the call to the setter method
-         *        now that the value to be written has been pushed by our caller.
-         */
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (idxProp.setProp != null) {
-                this.setProp.CallPost (scg, errorAt);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Pop);
-            }
-        }
-
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            // if no getter, reading would throw an error, so doesn't really matter what we say
-            if (idxProp.getProp == null) return true;
-
-            // assume interface methods are always non-trivial because we don't know anything about the actual implementation
-            if (baseRVal.type is TokenTypeSDTypeInterface) return false;
-
-            // accessing it in any way can't be trivial if reading the pointer isn't trivial
-            if (!baseRVal.IsReadTrivial (scg, readAt)) return false;
-
-            // likewise with the indices
-            foreach (CompValu idx in indices) {
-                if (!idx.IsReadTrivial (scg, readAt)) return false;
-            }
-
-            // now the only way it can be non-trivial to read is if the getter() method itself is non-trivial.
-            return idxProp.getProp.IsFuncTrivial (scg);
-        }
-
-        /**
-         * @brief Get how to call the getter or setter method.
-         */
-        private CompValu GetIdxPropMeth (TokenDeclVar meth)
-        {
-            if (baseRVal.type is TokenTypeSDTypeClass) {
-                return new CompValuInstMember (meth, baseRVal, false);
-            }
-            return new CompValuIntfMember (meth, baseRVal);
-        }
-    }
-
-    // This represents the type and location of an internally-defined function
-    // that a script can call
-    public class CompValuInline : CompValu {
-        public TokenDeclInline declInline;
-
-        public CompValuInline (TokenDeclInline declInline) : base (declInline.GetDelType ())
-        {
-            this.declInline = declInline;
-        }
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot use built-in for delegate, wrap it");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot use built-in for delegate, wrap it");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot use built-in for delegate, wrap it");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot use built-in for delegate, wrap it");
-            scg.ilGen.Emit (errorAt, OpCodes.Pop);
-        }
-    }
-
-    // The value is the entrypoint of a script-defined type's interface method combined with
-    // the pointer used to access the method.  Thus there is one of these per call site.
-    // They also handle accessing interface properties.
-    public class CompValuIntfMember : CompValu {
-        private TokenDeclVar declVar;
-        private CompValu baseRVal;
-
-        public CompValuIntfMember (TokenDeclVar declVar, CompValu baseRVal) : base (declVar.type)
-        {
-            if (this.type == null) throw new Exception ("interface member type is null");
-            this.declVar  = declVar;   // which element of the baseRVal vector to be accessed
-            this.baseRVal = baseRVal;  // the vector of delegates implementing the interface
-        }
-
-        /**
-         * @brief Reading a method's value means getting a delegate to that method.
-         *        Reading a property's value means calling the getter method for that property.
-         */
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.retType != null) {
-                baseRVal.PushVal (scg, errorAt);                        // push pointer to delegate array on stack
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select which delegate to access
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (Delegate));     // push delegate on stack
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, type.ToSysType ());  // cast to correct delegate class
-            } else if (declVar.getProp != null) {
-                CompValu getProp = new CompValuIntfMember (declVar.getProp, baseRVal);
-                getProp.CallPre  (scg, errorAt);                        // reading property, call its getter
-                getProp.CallPost (scg, errorAt);                        // ... with no arguments
-            } else {
-                scg.ErrorMsg (errorAt, "member not readable");
-                scg.PushDefaultValue (declVar.type);
-            }
-        }
-
-        /**
-         * @brief Can't get the address of either a method or a property.
-         */
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "member has no address");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-
-        /**
-         * @brief Can't write a method.
-         *        For property, it means calling the setter method for that property.
-         */
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.setProp == null) {
-                // read-only property
-                scg.ErrorMsg (errorAt, "member not writable");
-            }
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.setProp != null) {
-                CompValu setProp = new CompValuIntfMember (declVar.setProp, baseRVal);
-                EmitPopPostProp (scg, errorAt, declVar.type, setProp);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Pop);
-            }
-        }
-
-        /**
-         * @brief Reading a method (ie, it's delegate) is always trivial, it's just retrieving
-         *        an element from the delegate array that make up the interface object.
-         *
-         *        Reading a property is always non-trivial because we don't know which implementation 
-         *        the interface is pointing to, so we don't know if it's trivial or not, so assume 
-         *        the worst, ie, that it is non-trivial and might call CheckRun().
-         *
-         *        But all that assumes that locating the interface object in the first place is 
-         *        trivial, ie, baseRVal.PushVal() must not call CheckRun() either.
-         */
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return baseRVal.IsReadTrivial (scg, readAt) && (declVar.getProp == null);
-        }
-
-        /**
-         * @brief We just defer to the default CallPre() and CallPost() methods.
-         *        They expect this.PushVal() to push a delegate to the method to be called.
-         *        If this member is a method, our PushVal() will read the correct element 
-         *        of the iTable array and push it on the stack, ready for Invoke() to be
-         *        called.  If this member is a property, the only way it can be called is 
-         *        if the property is a delegate, in which case PushVal() will retrieve the 
-         *        delegate by calling the property's getter method.
-         */
-    }
-
-    // The value is the entrypoint of an internal instance method
-    // such as XMR_Array.index()
-    public class CompValuIntInstMeth : CompValu {
-        private TokenTypeSDTypeDelegate delType;
-        private CompValu baseRVal;
-        private MethodInfo methInfo;
-
-        public CompValuIntInstMeth (TokenTypeSDTypeDelegate delType, CompValu baseRVal, MethodInfo methInfo) : base (delType)
-        {
-            this.delType  = delType;
-            this.baseRVal = baseRVal;
-            this.methInfo = methInfo;
-        }
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            // its value, ie, without applying the (arglist), is a delegate...
-            baseRVal.PushVal (scg, errorAt);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldftn, methInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, delType.decl.GetConstructorInfo ());
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get ref to instance method");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into instance method");
-        }
-
-        public override void CallPre (ScriptCodeGen scg, Token errorAt)
-        {
-            // internal instance methods are always trivial so never need a CallLabel.
-            baseRVal.PushVal (scg, errorAt);
-        }
-        public override void CallPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
-        }
-    }
-
-    // The value is fetched by calling an internal instance method
-    // such as XMR_Array.count
-    public class CompValuIntInstROProp : CompValu {
-        private CompValu baseRVal;
-        private MethodInfo methInfo;
-
-        public CompValuIntInstROProp (TokenType valType, CompValu baseRVal, MethodInfo methInfo) : base (valType)
-        {
-            this.baseRVal = baseRVal;
-            this.methInfo = methInfo;
-        }
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            baseRVal.PushVal (scg, errorAt);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot get ref to read-only property");
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot store into read-only property");
-            scg.ilGen.Emit (errorAt, OpCodes.Pop);
-        }
-    }
-
-    // The value is in a member of a script-defined type class instance.
-    //       field: value is in one of the arrays contained within XMRSDTypeClObj.instVars
-    //      method: value is a delegate; can be called
-    //    property: reading and writing is via a method call
-    public class CompValuInstMember : CompValu {
-        private static readonly FieldInfo instVarsFieldInfo = typeof (XMRSDTypeClObj).GetField ("instVars");
-        private static readonly FieldInfo vTableFieldInfo   = typeof (XMRSDTypeClObj).GetField ("sdtcVTable");
-
-        private TokenDeclVar declVar;  // member being accessed
-        private CompValu baseRVal;     // pointer to particular object instance
-        private bool ignoreVirt;       // ignore virtual attribute; use declVar's non-virtual method/property
-
-        public CompValuInstMember (TokenDeclVar declVar, CompValu baseRVal, bool ignoreVirt) : base (declVar.type)
-        {
-            this.declVar    = declVar;
-            this.baseRVal   = baseRVal;
-            this.ignoreVirt = ignoreVirt;
-        }
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.retType != null) {
-                // a method's value, ie, without applying the (arglist), is a delegate...
-                PushValMethod (scg, errorAt);
-            } else if (declVar.vTableArray != null) {
-                // a field's value is its XMRSDTypeClObj.instVars array element
-                baseRVal.PushVal (scg, errorAt);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, instVarsFieldInfo);
-                EmitFieldPushVal (scg, errorAt, declVar);
-            } else if (declVar.getProp != null) {
-                // a property's value is calling its get method with no arguments
-                CompValu getProp = new CompValuInstMember (declVar.getProp, baseRVal, ignoreVirt);
-                getProp.CallPre  (scg, errorAt);
-                getProp.CallPost (scg, errorAt);
-            } else {
-                // write-only property
-                scg.ErrorMsg (errorAt, "member not readable");
-                scg.PushDefaultValue (declVar.type);
-            }
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.vTableArray != null) {
-                // a field's value is its XMRSDTypeClObj.instVars array element
-                baseRVal.PushVal (scg, errorAt);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, instVarsFieldInfo);
-                EmitFieldPushRef (scg, errorAt, declVar);
-            } else {
-                scg.ErrorMsg (errorAt, "member has no address");
-                scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-            }
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.vTableArray != null) {
-                // a field's value is its XMRSDTypeClObj.instVars array element
-                baseRVal.PushVal (scg, errorAt);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, instVarsFieldInfo);
-                EmitFieldPopPre (scg, errorAt, declVar);
-            } else if (declVar.setProp == null) {
-                // read-only property
-                scg.ErrorMsg (errorAt, "member not writable");
-            }
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.vTableArray != null) {
-                EmitFieldPopPost (scg, errorAt, declVar);
-            } else if (declVar.setProp != null) {
-                CompValu setProp = new CompValuInstMember (declVar.setProp, baseRVal, ignoreVirt);
-                EmitPopPostProp (scg, errorAt, declVar.type, setProp);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Pop);
-            }
-        }
-
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            // accessing it in any way can't be trivial if reading the pointer isn't trivial.
-            // this also handles strict right-to-left mode detection as the side-effect can
-            // only apply to the pointer (it can't change which field or method we access).
-            if (!baseRVal.IsReadTrivial (scg, readAt)) return false;
-
-            // now the only way it can be non-trivial to read is if it is a property and the 
-            // getter() method is non-trivial.  reading a method means getting a delegate 
-            // which is always trivial, and reading a simple field is always trivial, ie, no 
-            // CheckRun() call can possibly be involved.
-            if (declVar.retType != null) {
-                // a method's value, ie, without applying the (arglist), is a delegate...
-                return true;
-            }
-            if (declVar.vTableArray != null) {
-                // a field's value is its XMRSDTypeClObj.instVars array element
-                return true;
-            }
-            if (declVar.getProp != null) {
-                // a property's value is calling its get method with no arguments
-                return declVar.getProp.IsFuncTrivial (scg);
-            }
-
-            // write-only property
-            return true;
-        }
-
-        public override void CallPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.retType != null) {
-                CallPreMethod (scg, errorAt);
-            } else {
-                base.CallPre (scg, errorAt);
-            }
-        }
-        public override void CallPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (declVar.retType != null) {
-                CallPostMethod (scg, errorAt);
-            } else {
-                base.CallPost (scg, errorAt);
-            }
-        }
-
-        /**
-         * @brief A PushVal() for a method means to push a delegate for the method on the stack.
-         */
-        private void PushValMethod (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0) throw new Exception ("dont use for statics");
-
-            if (ignoreVirt || (declVar.vTableIndex < 0)) {
-
-                /*
-                 * Non-virtual instance method, create a delegate that references the method.
-                 */
-                string dtn = type.ToString ();
-
-                // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
-                //   where methName = <sdtclass>.<methname>(<argtypes>)
-                //        signature = <rettype>(<argtypes>)
-                //             arg0 = sdt istance (XMRSDTypeClObj) 'this' value
-                scg.PushXMRInst ();                                     // [0] scriptinstance
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, declVar.ilGen.methName); // [1] method name
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, dtn);                    // [2] delegate type name
-                baseRVal.PushVal (scg, errorAt);                        // [3] sdtinstance
-                scg.ilGen.Emit (errorAt, OpCodes.Callvirt, gsmdMethodInfo);      // [0] delegate instance
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, type.ToSysType ());  // [0] cast to correct delegate class
-            } else {
-
-                /*
-                 * Virtual instance method, get the delegate from the vtable.
-                 */
-                baseRVal.PushVal (scg, errorAt);                                 // 'this' selecting the instance
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, vTableFieldInfo);        // get pointer to instance's vtable array
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select vtable element
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (Delegate));     // get delegate pointer = 'this' for 'Invoke()'
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, type.ToSysType ());  // cast to correct delegate class
-            }
-        }
-
-        private void CallPreMethod (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0) throw new Exception ("dont use for statics");
-
-            if (!this.declVar.IsFuncTrivial (scg)) new ScriptCodeGen.CallLabel (scg, errorAt);
-
-            if (ignoreVirt || (declVar.vTableIndex < 0)) {
-                baseRVal.PushVal (scg, errorAt);                                 // 'this' being passed directly to method
-            } else {
-                baseRVal.PushVal (scg, errorAt);                                 // 'this' selecting the instance
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, vTableFieldInfo);        // get pointer to instance's vtable array
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select vtable element
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (Delegate));     // get delegate pointer = 'this' for 'Invoke()'
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, type.ToSysType ());  // cast to correct delegate class
-            }
-        }
-        private void CallPostMethod (ScriptCodeGen scg, Token errorAt)
-        {
-            if (ignoreVirt || (declVar.vTableIndex < 0)) {
-                // non-virt instance, just call function directly
-                scg.ilGen.Emit (errorAt, OpCodes.Call, declVar.ilGen);
-            } else {
-                // virtual, call via delegate Invoke(...) method
-                TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
-                MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo ();
-                scg.ilGen.Emit (errorAt, OpCodes.Callvirt, invokeMethodInfo);
-            }
-
-            if (!this.declVar.IsFuncTrivial (scg)) scg.openCallLabel = null;
-        }
-    }
-
-    // The value is an integer constant
-    public class CompValuInteger : CompValu {
-        public int x;
-
-        public CompValuInteger (TokenType type, int x) : base (type)
-        {
-            if (!(this.type is TokenTypeInt)) {
-                this.type = new TokenTypeInt (this.type);
-            }
-            this.x = x;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, x);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into constant");
-        }
-    }
-
-    // The value is an element of a list
-    public class CompValuListEl : CompValu {
-        private static readonly MethodInfo getElementFromListMethodInfo = 
-                 typeof (CompValuListEl).GetMethod ("GetElementFromList", new Type[] { typeof (LSL_List), typeof (int) });
-
-        private CompValu theList;
-        private CompValu subscript;
-
-        public CompValuListEl (TokenType type, CompValu theList, CompValu subscript) : base (type)
-        {
-            this.theList   = theList;
-            this.subscript = subscript;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            theList.PushVal (scg, errorAt, new TokenTypeList (type));
-            subscript.PushVal (scg, errorAt, new TokenTypeInt (type));
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getElementFromListMethodInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get list element's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot store into list element");
-            scg.ilGen.Emit (errorAt, OpCodes.Pop);
-        }
-
-        public static object GetElementFromList (LSL_List lis, int idx)
-        {
-            object element = lis.Data[idx];
-            if (element is LSL_Float)                return TypeCast.EHArgUnwrapFloat    (element);
-            if (element is LSL_Integer)              return TypeCast.EHArgUnwrapInteger  (element);
-            if (element is LSL_String)               return TypeCast.EHArgUnwrapString   (element);
-            if (element is OpenMetaverse.Quaternion) return TypeCast.EHArgUnwrapRotation (element);
-            if (element is OpenMetaverse.Vector3)    return TypeCast.EHArgUnwrapVector   (element);
-            return element;
-        }
-    }
-
-    // The value is kept in a script-addressable local variable
-    public class CompValuLocalVar : CompValu {
-        private static int htpopseq = 0;
-
-        private ScriptMyLocal localBuilder;
-
-        public CompValuLocalVar (TokenType type, string name, ScriptCodeGen scg) : base (type)
-        {
-            if (type.ToHeapTrackerType () != null) {
-                this.localBuilder = scg.ilGen.DeclareLocal (type.ToHeapTrackerType (), name);
-                scg.PushXMRInst ();
-                scg.ilGen.Emit (type, OpCodes.Newobj, type.GetHeapTrackerCtor ());
-                scg.ilGen.Emit (type, OpCodes.Stloc, localBuilder);
-            } else {
-                this.localBuilder = scg.ilGen.DeclareLocal (ToSysType (), name);
-            }
-        }
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder);
-            if (type.ToHeapTrackerType () != null) {
-                type.CallHeapTrackerPushMeth (errorAt, scg.ilGen);
-            }
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if (type.ToHeapTrackerType () != null) {
-                scg.ErrorMsg (errorAt, "can't take ref of heap-tracked type " + type.ToString ());
-                scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldloca, localBuilder);
-            }
-        }
-
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-            if (type.ToHeapTrackerType () != null) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder);
-            }
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if (type.ToHeapTrackerType () != null) {
-                type.CallHeapTrackerPopMeth (errorAt, scg.ilGen);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Stloc, localBuilder);
-            }
-        }
-
-        public void Pop (ScriptCodeGen scg, Token errorAt)
-        {
-            if (type.ToHeapTrackerType () != null) {
-                /*
-                 * Popping into a heap tracker wrapped local variable.
-                 * First pop value into a temp var, then call the heap tracker's pop method.
-                 */
-                ScriptMyLocal htpop = scg.ilGen.DeclareLocal (type.ToSysType (), "htpop$" + (++ htpopseq).ToString ());
-                scg.ilGen.Emit (errorAt, OpCodes.Stloc, htpop);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldloc, htpop);
-                type.CallHeapTrackerPopMeth (errorAt, scg.ilGen);
-            } else {
-
-                /*
-                 * Not a heap-tracked local var, just pop directly into it.
-                 */
-                scg.ilGen.Emit (errorAt, OpCodes.Stloc, localBuilder);
-            }
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading a
-        // local variable is trivial.
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // The value is a null
-    public class CompValuNull : CompValu {
-        public CompValuNull (TokenType type) : base (type) { }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldnull);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get null's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into null");
-        }
-    }
-
-    // The value is a rotation
-    public class CompValuRot : CompValu {
-        public CompValu x;
-        public CompValu y;
-        public CompValu z;
-        public CompValu w;
-
-        private static readonly ConstructorInfo lslRotConstructorInfo = 
-                typeof (LSL_Rotation).GetConstructor (new Type[] { typeof (double), 
-                                                                   typeof (double), 
-                                                                   typeof (double), 
-                                                                   typeof (double) });
-
-        public CompValuRot (TokenType type, CompValu x, CompValu y, CompValu z, CompValu w) :
-                base (type)
-        {
-            if (!(type is TokenTypeRot)) {
-                this.type = new TokenTypeRot (type);
-            }
-            this.x = x;
-            this.y = y;
-            this.z = z;
-            this.w = w;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            this.x.PushVal (scg, errorAt, new TokenTypeFloat (this.x.type));
-            this.y.PushVal (scg, errorAt, new TokenTypeFloat (this.y.type));
-            this.z.PushVal (scg, errorAt, new TokenTypeFloat (this.z.type));
-            this.w.PushVal (scg, errorAt, new TokenTypeFloat (this.w.type));
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslRotConstructorInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into constant");
-        }
-
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            // the supplied values must be trivial because when we call their PushVal()s
-            // there will be stuff on the stack for all but the first PushVal() and so
-            // they would have a non-empty stack at their call label.
-            if (!this.w.IsReadTrivial (scg, readAt) ||
-                !this.x.IsReadTrivial (scg, readAt) ||
-                !this.y.IsReadTrivial (scg, readAt) ||
-                !this.z.IsReadTrivial (scg, readAt)) {
-                throw new Exception ("rotation values must be trivial");
-            }
-
-            return true;
-        }
-    }
-
-    // The value is in a static field of an internally defined struct/class
-    public class CompValuSField : CompValu {
-        public FieldInfo field;
-
-        public CompValuSField (TokenType type, FieldInfo field) : base (type)
-        {
-            this.field = field;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((field.Attributes & FieldAttributes.Literal) == 0) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldsfld, field);
-                return;
-            }
-            if (field.FieldType == typeof (LSL_Rotation)) {
-                LSL_Rotation rot = (LSL_Rotation)field.GetValue (null);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, rot.x);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, rot.y);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, rot.z);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, rot.s);
-                scg.ilGen.Emit (errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
-                return;
-            }
-            if (field.FieldType == typeof (LSL_Vector)) {
-                LSL_Vector vec = (LSL_Vector)field.GetValue (null);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, vec.x);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, vec.y);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_R8, vec.z);
-                scg.ilGen.Emit (errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
-                return;
-            }
-            if (field.FieldType == typeof (string)) {
-                string str = (string)field.GetValue (null);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, str);
-                return;
-            }
-            throw new Exception ("unsupported literal type " + field.FieldType.Name);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((field.Attributes & FieldAttributes.Literal) != 0) {
-                throw new Exception ("can't write a constant");
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Ldflda, field);
-        }
-        public override void PopPre (ScriptCodeGen scg, Token errorAt)
-        {
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            if ((field.Attributes & FieldAttributes.Literal) != 0) {
-                throw new Exception ("can't write a constant");
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Stsfld, field);
-        }
-
-        // non-trivial because it needs to be copied into a temp
-        // in case the idiot does dumb-ass side effects tricks
-        //   eg,  (x = 0) + x + 2
-        //   should read old value of x not 0
-        // but if 'xmroption norighttoleft;' in effect,
-        // we can read it in any order so reading a
-        // local variable is trivial.
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            return readAt.nr2l;
-        }
-    }
-
-    // The value is a character within a string
-    public class CompValuStrChr : CompValu {
-        private static readonly MethodInfo getCharFromStringMethodInfo = 
-                 typeof (CompValuStrChr).GetMethod ("GetCharFromString", new Type[] { typeof (string), typeof (int) });
-
-        private CompValu theString;
-        private CompValu subscript;
-
-        public CompValuStrChr (TokenType type, CompValu theString, CompValu subscript) : base (type)
-        {
-            this.theString = theString;
-            this.subscript = subscript;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            theString.PushVal (scg, errorAt, new TokenTypeStr (type));
-            subscript.PushVal (scg, errorAt, new TokenTypeInt (type));
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getCharFromStringMethodInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get string character's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ErrorMsg (errorAt, "cannot store into string character");
-            scg.ilGen.Emit (errorAt, OpCodes.Pop);
-        }
-
-        public static char GetCharFromString (string s, int i)
-        {
-            return s[i];
-        }
-    }
-
-    // The value is a key or string constant
-    public class CompValuString : CompValu {
-        public string x;
-
-        public CompValuString (TokenType type, string x) : base (type)
-        {
-            if (!(type is TokenTypeKey) && !(this.type is TokenTypeStr)) {
-                throw new Exception ("bad type " + type.ToString ());
-            }
-            this.x = x;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldstr, x);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into constant");
-        }
-    }
-
-    // The value is kept in a temp local variable
-    public class CompValuTemp : CompValu {
-        public ScriptMyLocal localBuilder;
-
-        public CompValuTemp (TokenType type, ScriptCodeGen scg) : base (type)
-        {
-            string name = "tmp$" + (++ scg.tempCompValuNum);
-            this.localBuilder = scg.ilGen.DeclareLocal (ToSysType(), name);
-        }
-        protected CompValuTemp (TokenType type) : base (type) { }  // CompValuVoid uses this
-
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldloca, localBuilder);
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Stloc, localBuilder);
-        }
-        public void Pop (ScriptCodeGen scg, Token errorAt, TokenType stackType)
-        {
-            TypeCast.CastTopOfStack (scg, errorAt, stackType, this.type, false);
-            this.PopPost (scg, errorAt);  // in case PopPost() overridden eg by CompValuVoid
-        }
-        public void Pop (ScriptCodeGen scg, Token errorAt)
-        {
-            this.PopPost (scg, errorAt);  // in case PopPost() overridden eg by CompValuVoid
-        }
-    }
-
-    // The value is a vector
-    public class CompValuVec : CompValu {
-        public CompValu x;
-        public CompValu y;
-        public CompValu z;
-
-        private static readonly ConstructorInfo lslVecConstructorInfo = 
-                typeof (LSL_Vector).GetConstructor (new Type[] { typeof (double), 
-                                                                 typeof (double), 
-                                                                 typeof (double) });
-
-        public CompValuVec (TokenType type, CompValu x, CompValu y, CompValu z) : base (type)
-        {
-            if (!(type is TokenTypeVec)) {
-                this.type = new TokenTypeVec (type);
-            }
-            this.x = x;
-            this.y = y;
-            this.z = z;
-        }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt)
-        {
-            this.x.PushVal (scg, errorAt, new TokenTypeFloat (this.x.type));
-            this.y.PushVal (scg, errorAt, new TokenTypeFloat (this.y.type));
-            this.z.PushVal (scg, errorAt, new TokenTypeFloat (this.z.type));
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslVecConstructorInfo);
-        }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get constant's address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot store into constant");
-        }
-
-        public override bool IsReadTrivial (ScriptCodeGen scg, Token readAt)
-        {
-            // the supplied values must be trivial because when we call their PushVal()s
-            // there will be stuff on the stack for all but the first PushVal() and so
-            // they would have a non-empty stack at their call label.
-            if (!this.x.IsReadTrivial (scg, readAt) ||
-                !this.y.IsReadTrivial (scg, readAt) ||
-                !this.z.IsReadTrivial (scg, readAt)) {
-                throw new Exception ("vector values must be trivial");
-            }
-
-            return true;
-        }
-    }
-
-    // Used to indicate value will be discarded (eg, where to put return value from a call)
-    public class CompValuVoid : CompValuTemp {
-        public CompValuVoid (Token token) : base ((token is TokenTypeVoid) ? (TokenTypeVoid)token : new TokenTypeVoid (token))
-        { }
-        public override void PushVal (ScriptCodeGen scg, Token errorAt) { }
-        public override void PushRef (ScriptCodeGen scg, Token errorAt)
-        {
-            throw new Exception ("cannot get void address");
-        }
-        public override void PopPost (ScriptCodeGen scg, Token errorAt) { }
-    }
-}

+ 0 - 250
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptConsts.cs

@@ -1,250 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Text;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine {
-
-    public class ScriptConst {
-
-        public static Dictionary<string, ScriptConst> scriptConstants = Init ();
-
-        /**
-         * @brief look up the value of a given built-in constant.
-         * @param name = name of constant
-         * @returns null: no constant by that name defined
-         *          else: pointer to ScriptConst struct
-         */
-        public static ScriptConst Lookup (string name)
-        {
-            ScriptConst sc;
-            if (!scriptConstants.TryGetValue (name, out sc)) sc = null;
-            return sc;
-        }
-
-        private static Dictionary<string, ScriptConst> Init ()
-        {
-            Dictionary<string, ScriptConst> sc = new Dictionary<string, ScriptConst> ();
-
-            /*
-             * For every event code, define XMREVENTCODE_<eventname> and XMREVENTMASKn_<eventname> symbols.
-             */
-            for (int i = 0; i < 64; i ++) {
-                try {
-                    string s = ((ScriptEventCode)i).ToString ();
-                    if ((s.Length > 0) && (s[0] >= 'a') && (s[0] <= 'z')) {
-                        new ScriptConst (sc, 
-                                         "XMREVENTCODE_" + s, 
-                                         new CompValuInteger (new TokenTypeInt (null), i));
-                        int n = i / 32 + 1;
-                        int m = 1 << (i % 32);
-                        new ScriptConst (sc, 
-                                         "XMREVENTMASK" + n + "_" + s, 
-                                         new CompValuInteger (new TokenTypeInt (null), m));
-                    }
-                } catch { }
-            }
-
-            /*
-             * Also get all the constants from XMRInstAbstract and ScriptBaseClass etc as well.
-             */
-            for (Type t = typeof (XMRInstAbstract); t != typeof (object); t = t.BaseType) {
-                AddInterfaceConstants (sc, t.GetFields ());
-            }
-
-            return sc;
-        }
-
-        /**
-         * @brief Add all constants defined by the given interface.
-         */
-        // this one accepts only upper-case named fields
-        public static void AddInterfaceConstants (Dictionary<string, ScriptConst> sc, FieldInfo[] allFields)
-        {
-            List<FieldInfo> ucfs = new List<FieldInfo> (allFields.Length);
-            foreach (FieldInfo f in allFields) {
-                string fieldName = f.Name;
-                int i;
-                for (i = fieldName.Length; -- i >= 0;) {
-                    if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".IndexOf (fieldName[i]) < 0) break;
-                }
-                if (i < 0) ucfs.Add (f);
-            }
-            AddInterfaceConstants (sc, ucfs.GetEnumerator ());
-        }
-
-        // this one accepts all fields given to it
-        public static void AddInterfaceConstants (Dictionary<string, ScriptConst> sc, IEnumerator<FieldInfo> fields)
-        {
-            if (sc == null) sc = scriptConstants;
-
-            for (fields.Reset (); fields.MoveNext ();) {
-                FieldInfo constField = fields.Current;
-                Type fieldType = constField.FieldType;
-                CompValu cv;
-
-                /*
-                 * The location of a simple number is the number itself.
-                 * Access to the value gets compiled as an ldc instruction.
-                 */
-                if (fieldType == typeof (double)) {
-                    cv = new CompValuFloat (new TokenTypeFloat (null),
-                                            (double)(double)constField.GetValue (null));
-                } else if (fieldType == typeof (int)) {
-                    cv = new CompValuInteger (new TokenTypeInt (null),
-                                              (int)constField.GetValue (null));
-                } else if (fieldType == typeof (LSL_Integer)) {
-                    cv = new CompValuInteger (new TokenTypeInt (null),
-                                              ((LSL_Integer)constField.GetValue (null)).value);
-                }
-
-                /*
-                 * The location of a string is the string itself.
-                 * Access to the value gets compiled as an ldstr instruction.
-                 */
-                else if (fieldType == typeof (string)) {
-                    cv = new CompValuString (new TokenTypeStr (null), 
-                                             (string)constField.GetValue (null));
-                } else if (fieldType == typeof (LSL_String)) {
-                    cv = new CompValuString (new TokenTypeStr (null), 
-                                             (string)(LSL_String)constField.GetValue (null));
-                }
-
-                /*
-                 * The location of everything else (objects) is the static field in the interface definition.
-                 * Access to the value gets compiled as an ldsfld instruction.
-                 */
-                else {
-                    cv = new CompValuSField (TokenType.FromSysType (null, fieldType), constField);
-                }
-
-                /*
-                 * Add to dictionary.
-                 */
-                new ScriptConst (sc, constField.Name, cv);
-            }
-        }
-
-        /**
-         * @brief Add arbitrary constant available to script compilation.
-         * CAUTION: These values get compiled-in to a script and must not
-         *          change over time as previously compiled scripts will
-         *          still have the old values.
-         */
-        public static ScriptConst AddConstant (string name, object value)
-        {
-            CompValu cv = null;
-
-            if (value is char) {
-                cv = new CompValuChar (new TokenTypeChar (null), (char)value);
-            }
-            if (value is double) {
-                cv = new CompValuFloat (new TokenTypeFloat (null), (double)(double)value);
-            }
-            if (value is float) {
-                cv = new CompValuFloat (new TokenTypeFloat (null), (double)(float)value);
-            }
-            if (value is int) {
-                cv = new CompValuInteger (new TokenTypeInt (null), (int)value);
-            }
-            if (value is string) {
-                cv = new CompValuString (new TokenTypeStr (null), (string)value);
-            }
-
-            if (value is LSL_Float) {
-                cv = new CompValuFloat (new TokenTypeFloat (null), (double)((LSL_Float)value).value);
-            }
-            if (value is LSL_Integer) {
-                cv = new CompValuInteger (new TokenTypeInt (null), ((LSL_Integer)value).value);
-            }
-            if (value is LSL_Rotation) {
-                LSL_Rotation r = (LSL_Rotation)value;
-                CompValu x = new CompValuFloat (new TokenTypeFloat (null), r.x);
-                CompValu y = new CompValuFloat (new TokenTypeFloat (null), r.y);
-                CompValu z = new CompValuFloat (new TokenTypeFloat (null), r.z);
-                CompValu s = new CompValuFloat (new TokenTypeFloat (null), r.s);
-                cv = new CompValuRot (new TokenTypeRot (null), x, y, z, s);
-            }
-            if (value is LSL_String) {
-                cv = new CompValuString (new TokenTypeStr (null), (string)(LSL_String)value);
-            }
-            if (value is LSL_Vector) {
-                LSL_Vector v = (LSL_Vector)value;
-                CompValu x = new CompValuFloat (new TokenTypeFloat (null), v.x);
-                CompValu y = new CompValuFloat (new TokenTypeFloat (null), v.y);
-                CompValu z = new CompValuFloat (new TokenTypeFloat (null), v.z);
-                cv = new CompValuVec (new TokenTypeVec (null), x, y, z);
-            }
-
-            if (value is OpenMetaverse.Quaternion) {
-                OpenMetaverse.Quaternion r = (OpenMetaverse.Quaternion)value;
-                CompValu x = new CompValuFloat (new TokenTypeFloat (null), r.X);
-                CompValu y = new CompValuFloat (new TokenTypeFloat (null), r.Y);
-                CompValu z = new CompValuFloat (new TokenTypeFloat (null), r.Z);
-                CompValu s = new CompValuFloat (new TokenTypeFloat (null), r.W);
-                cv = new CompValuRot (new TokenTypeRot (null), x, y, z, s);
-            }
-            if (value is OpenMetaverse.UUID) {
-                cv = new CompValuString (new TokenTypeKey (null), value.ToString ());
-            }
-            if (value is OpenMetaverse.Vector3) {
-                OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)value;
-                CompValu x = new CompValuFloat (new TokenTypeFloat (null), v.X);
-                CompValu y = new CompValuFloat (new TokenTypeFloat (null), v.Y);
-                CompValu z = new CompValuFloat (new TokenTypeFloat (null), v.Z);
-                cv = new CompValuVec (new TokenTypeVec (null), x, y, z);
-            }
-
-            if (cv == null) throw new Exception ("bad type " + value.GetType ().Name);
-            return new ScriptConst (scriptConstants, name, cv);
-        }
-
-        /*
-         * Instance variables
-         */
-        public string name;
-        public CompValu rVal;
-
-        private ScriptConst (Dictionary<string, ScriptConst> lc, string name, CompValu rVal)
-        {
-            lc.Add (name, this);
-            this.name = name;
-            this.rVal = rVal;
-        }
-    }
-}

+ 0 - 666
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptInlines.cs

@@ -1,666 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * @brief Generate code for the backend API calls.
- */
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public abstract class TokenDeclInline : TokenDeclVar {
-        public static VarDict inlineFunctions = CreateDictionary ();
-
-        public abstract void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args);
-
-        private static string[] noCheckRuns;
-        private static string[] keyReturns;
-
-        protected bool isTaggedCallsCheckRun;
-
-        /**
-         * @brief Create a dictionary of inline backend API functions.
-         */
-        private static VarDict CreateDictionary ()
-        {
-            /*
-             * For those listed in noCheckRun, we just generate the call (simple computations).
-             * For all others, we generate the call then a call to CheckRun().
-             */
-            noCheckRuns = new string[] {
-                "llBase64ToString",
-                "llCSV2List",
-                "llDeleteSubList",
-                "llDeleteSubString",
-                "llDumpList2String",
-                "llEscapeURL",
-                "llEuler2Rot",
-                "llGetListEntryType",
-                "llGetListLength",
-                "llGetSubString",
-                "llGetUnixTime",
-                "llInsertString",
-                "llList2CSV",
-                "llList2Float",
-                "llList2Integer",
-                "llList2Key",
-                "llList2List",
-                "llList2ListStrided",
-                "llList2Rot",
-                "llList2String",
-                "llList2Vector",
-                "llListFindList",
-                "llListInsertList",
-                "llListRandomize",
-                "llListReplaceList",
-                "llListSort",
-                "llListStatistics",
-                "llMD5String",
-                "llParseString2List",
-                "llParseStringKeepNulls",
-                "llRot2Euler",
-                "llStringLength",
-                "llStringToBase64",
-                "llStringTrim",
-                "llSubStringIndex",
-                "llUnescapeURL"
-            };
-
-            /*
-             * These functions really return a 'key' even though we see them as
-             * returning 'string' because OpenSim has key and string as same type.
-             */
-            keyReturns = new string[] {
-                "llAvatarOnLinkSitTarget",
-                "llAvatarOnSitTarget",
-                "llDetectedKey",
-                "llDetectedOwner",
-                "llGenerateKey",
-                "llGetCreator",
-                "llGetInventoryCreator",
-                "llGetInventoryKey",
-                "llGetKey",
-                "llGetLandOwnerAt",
-                "llGetLinkKey",
-                "llGetNotecardLine",
-                "llGetNumberOfNotecardLines",
-                "llGetOwner",
-                "llGetOwnerKey",
-                "llGetPermissionsKey",
-                "llHTTPRequest",
-                "llList2Key",
-                "llRequestAgentData",
-                "llRequestDisplayName",
-                "llRequestInventoryData",
-                "llRequestSecureURL",
-                "llRequestSimulatorData",
-                "llRequestURL",
-                "llRequestUsername",
-                "llSendRemoteData",
-                "llTransferLindenDollars"
-            };
-
-            VarDict ifd = new VarDict (false);
-
-            Type[] oneDoub  = new Type[] { typeof (double) };
-            Type[] twoDoubs = new Type[] { typeof (double), typeof (double) };
-
-            /*
-             * Mono generates an FPU instruction for many math calls.
-             */
-            new TokenDeclInline_LLAbs   (ifd);
-            new TokenDeclInline_Math    (ifd, "llAcos(float)",        "Acos",  oneDoub);
-            new TokenDeclInline_Math    (ifd, "llAsin(float)",        "Asin",  oneDoub);
-            new TokenDeclInline_Math    (ifd, "llAtan2(float,float)", "Atan2", twoDoubs);
-            new TokenDeclInline_Math    (ifd, "llCos(float)",         "Cos",   oneDoub);
-            new TokenDeclInline_Math    (ifd, "llFabs(float)",        "Abs",   oneDoub);
-            new TokenDeclInline_Math    (ifd, "llLog(float)",         "Log",   oneDoub);
-            new TokenDeclInline_Math    (ifd, "llLog10(float)",       "Log10", oneDoub);
-            new TokenDeclInline_Math    (ifd, "llPow(float,float)",   "Pow",   twoDoubs);
-            new TokenDeclInline_LLRound (ifd);
-            new TokenDeclInline_Math    (ifd, "llSin(float)",         "Sin",   oneDoub);
-            new TokenDeclInline_Math    (ifd, "llSqrt(float)",        "Sqrt",  oneDoub);
-            new TokenDeclInline_Math    (ifd, "llTan(float)",         "Tan",   oneDoub);
-
-            /*
-             * Something weird about the code generation for these calls, so they all have their own handwritten code generators.
-             */
-            new TokenDeclInline_GetFreeMemory (ifd);
-            new TokenDeclInline_GetUsedMemory (ifd);
-
-            /*
-             * These are all the xmr...() calls directly in XMRInstAbstract.
-             * Includes the calls from ScriptBaseClass that has all the stubs
-             * which convert XMRInstAbstract to the various <NAME>_Api contexts.
-             */
-            MethodInfo[] absmeths = typeof (XMRInstAbstract).GetMethods ();
-            AddInterfaceMethods (ifd, absmeths, null);
-
-            return ifd;
-        }
-
-        /**
-         * @brief Add API functions from the given interface to list of built-in functions.
-         *        Only functions beginning with a lower-case letter are entered, all others ignored.
-         * @param ifd = internal function dictionary to add them to
-         * @param ifaceMethods = list of API functions
-         * @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer
-         */
-        // this one accepts only names beginning with a lower-case letter
-        public static void AddInterfaceMethods (VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf)
-        {
-            List<MethodInfo> lcms = new List<MethodInfo> (ifaceMethods.Length);
-            foreach (MethodInfo meth in ifaceMethods)
-            {
-                string name = meth.Name;
-                if ((name[0] >= 'a') && (name[0] <= 'z')) {
-                    lcms.Add (meth);
-                }
-            }
-            AddInterfaceMethods (ifd, lcms.GetEnumerator (), acf);
-        }
-
-        // this one accepts all methods given to it
-        public static void AddInterfaceMethods (VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf)
-        {
-            if (ifd == null) ifd = inlineFunctions;
-
-            for (ifaceMethods.Reset (); ifaceMethods.MoveNext ();) {
-                MethodInfo ifaceMethod = ifaceMethods.Current;
-                string key = ifaceMethod.Name;
-
-                try {
-                    /*
-                     * See if we will generate a call to CheckRun() right 
-                     * after we generate a call to the function.
-                     * If function begins with xmr, assume we will not call CheckRun()
-                     * Otherwise, assume we will call CheckRun()
-                     */
-                    bool dcr = !key.StartsWith ("xmr");
-                    foreach (string ncr in noCheckRuns) {
-                        if (ncr == key) {
-                            dcr = false;
-                            break;
-                        }
-                    }
-
-                    /*
-                     * Add function to dictionary.
-                     */
-                    new TokenDeclInline_BEApi (ifd, dcr, ifaceMethod, acf);
-                } catch {
-                    ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
-                    ///???                          and OVERLOADED NAMES ???///
-                }
-            }
-        }
-
-        /**
-         * @brief Add an inline function definition to the dictionary.
-         * @param ifd        = dictionary to add inline definition to
-         * @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun()
-         * @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...)
-         * @param retType    = return type, use TokenTypeVoid if no return value
-         */
-        protected TokenDeclInline (VarDict ifd, 
-                                   bool doCheckRun, 
-                                   string nameArgSig, 
-                                   TokenType retType)
-                : base (null, null, null)
-        {
-            this.retType    = retType;
-            this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial;
-
-            int j = nameArgSig.IndexOf ('(');
-            this.name = new TokenName (null, nameArgSig.Substring (0, j ++));
-
-            this.argDecl = new TokenArgDecl (null);
-            if (nameArgSig[j] != ')') {
-                int i;
-                TokenName name;
-                TokenType type;
-
-                for (i = j; nameArgSig[i] != ')'; i ++) {
-                    if (nameArgSig[i] == ',') {
-                        type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j));
-                        name = new TokenName (null, "arg" + this.argDecl.varDict.Count);
-                        this.argDecl.AddArg (type, name);
-                        j = i + 1;
-                    }
-                }
-
-                type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j));
-                name = new TokenName (null, "arg" + this.argDecl.varDict.Count);
-                this.argDecl.AddArg (type, name);
-            }
-
-            this.location = new CompValuInline (this);
-            if (ifd == null) ifd = inlineFunctions;
-            ifd.AddEntry (this);
-        }
-
-        protected TokenDeclInline (VarDict ifd, 
-                                   bool doCheckRun, 
-                                   MethodInfo methInfo)
-                : base (null, null, null)
-        {
-            TokenType retType = TokenType.FromSysType (null, methInfo.ReturnType);
-
-            this.isTaggedCallsCheckRun = IsTaggedCallsCheckRun (methInfo);
-            this.name       = new TokenName (null, methInfo.Name);
-            this.retType    = GetRetType (methInfo, retType);
-            this.argDecl    = GetArgDecl (methInfo.GetParameters ());
-            this.triviality = (doCheckRun || this.isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial;
-            this.location   = new CompValuInline (this);
-
-            if (ifd == null) ifd = inlineFunctions;
-            ifd.AddEntry (this);
-        }
-
-        private static TokenArgDecl GetArgDecl (ParameterInfo[] parameters)
-        {
-            TokenArgDecl argDecl = new TokenArgDecl (null);
-            foreach (ParameterInfo pi in parameters) {
-                TokenType type = TokenType.FromSysType (null, pi.ParameterType);
-                TokenName name = new TokenName (null, pi.Name);
-                argDecl.AddArg (type, name);
-            }
-            return argDecl;
-        }
-
-        /**
-         * @brief The above code assumes all methods beginning with 'xmr' are trivial, ie, 
-         *        they do not call CheckRun() and also we do not generate a CheckRun() 
-         *        call after they return.  So if an 'xmr' method does call CheckRun(), it 
-         *        must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know 
-         *        the method is not trivial.  But in neither case do we emit our own call 
-         *        to CheckRun(), the 'xmr' method must do its own.  We do however set up a
-         *        call label before the call to the non-trivial 'xmr' method so when we are
-         *        restoring the call stack, the restore will call directly in to the 'xmr'
-         *        method without re-executing any code before the call to the 'xmr' method.
-         */
-        private static bool IsTaggedCallsCheckRun (MethodInfo methInfo)
-        {
-            return (methInfo != null) &&
-                Attribute.IsDefined (methInfo, typeof (xmrMethodCallsCheckRunAttribute));
-        }
-
-        /**
-         * @brief The dumbass OpenSim has key and string as the same type so non-ll
-         *        methods must be tagged with xmrMethodReturnsKeyAttribute if we
-         *        are to think they return a key type, otherwise we will think they
-         *        return string.
-         */
-        private static TokenType GetRetType (MethodInfo methInfo, TokenType retType)
-        {
-            if ((methInfo != null) && (retType != null) && (retType is TokenTypeStr)) {
-                if (Attribute.IsDefined (methInfo, typeof (xmrMethodReturnsKeyAttribute))) {
-                    return ChangeToKeyType (retType);
-                }
-
-                string mn = methInfo.Name;
-                foreach (string kr in keyReturns) {
-                    if (kr == mn) return ChangeToKeyType (retType);
-                }
-
-            }
-            return retType;
-        }
-        private static TokenType ChangeToKeyType (TokenType retType)
-        {
-            if (retType is TokenTypeLSLString) {
-                retType = new TokenTypeLSLKey (null);
-            } else {
-                retType = new TokenTypeKey (null);
-            }
-            return retType;
-        }
-
-        public virtual MethodInfo GetMethodInfo ()
-        {
-            return null;
-        }
-
-        /**
-         * @brief Print out a list of all the built-in functions and constants.
-         */
-        public delegate void WriteLine (string str);
-        public static void PrintBuiltins (bool inclNoisyTag, WriteLine writeLine)
-        {
-            writeLine ("\nBuilt-in functions:\n");
-            SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline> ();
-            foreach (TokenDeclVar bif in TokenDeclInline.inlineFunctions) {
-                bifs.Add (bif.fullName, (TokenDeclInline)bif);
-            }
-            foreach (TokenDeclInline bif in bifs.Values) {
-                char noisy = (!inclNoisyTag || !IsTaggedNoisy (bif.GetMethodInfo ())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R';
-                writeLine (noisy + "   " + bif.retType.ToString ().PadLeft (8) + " " + bif.fullName);
-            }
-            if (inclNoisyTag) {
-                writeLine ("\nN - stub that writes name and arguments to stdout");
-                writeLine ("R - stub that writes name and arguments to stdout then reads return value from stdin");
-                writeLine ("    format is:  function_name : return_value");
-                writeLine ("      example:  llKey2Name:\"Kunta Kinte\"");
-            }
-
-            writeLine ("\nBuilt-in constants:\n");
-            SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst> ();
-            int widest = 0;
-            foreach (ScriptConst sc in ScriptConst.scriptConstants.Values) {
-                if (widest < sc.name.Length) widest = sc.name.Length;
-                scs.Add (sc.name, sc);
-            }
-            foreach (ScriptConst sc in scs.Values) {
-                writeLine ("    " + sc.rVal.type.ToString ().PadLeft (8) + " " + sc.name.PadRight (widest) + " = " + BuiltInConstVal (sc.rVal));
-            }
-        }
-
-        public static bool IsTaggedNoisy (MethodInfo methInfo)
-        {
-            return (methInfo != null) && Attribute.IsDefined (methInfo, typeof (xmrMethodIsNoisyAttribute));
-        }
-
-        public static string BuiltInConstVal (CompValu rVal)
-        {
-            if (rVal is CompValuInteger) {
-                int x = ((CompValuInteger)rVal).x;
-                return "0x" + x.ToString ("X8") + " = " + x.ToString ().PadLeft (11);
-            }
-            if (rVal is CompValuFloat) return ((CompValuFloat)rVal).x.ToString ();
-            if (rVal is CompValuString) {
-                StringBuilder sb = new StringBuilder ();
-                PrintParam (sb, ((CompValuString)rVal).x);
-                return sb.ToString ();
-            }
-            if (rVal is CompValuSField) {
-                FieldInfo fi = ((CompValuSField)rVal).field;
-                StringBuilder sb = new StringBuilder ();
-                PrintParam (sb, fi.GetValue (null));
-                return sb.ToString ();
-            }
-            return rVal.ToString ();  // just prints the type
-        }
-
-        public static void PrintParam (StringBuilder sb, object p)
-        {
-            if (p == null) {
-                sb.Append ("null");
-            } else if (p is LSL_List) {
-                sb.Append ('[');
-                object[] d = ((LSL_List)p).Data;
-                for (int i = 0; i < d.Length; i ++) {
-                    if (i > 0) sb.Append (',');
-                    PrintParam (sb, d[i]);
-                }
-                sb.Append (']');
-            } else if (p is LSL_Rotation) {
-                LSL_Rotation r = (LSL_Rotation)p;
-                sb.Append ('<');
-                sb.Append (r.x);
-                sb.Append (',');
-                sb.Append (r.y);
-                sb.Append (',');
-                sb.Append (r.z);
-                sb.Append (',');
-                sb.Append (r.s);
-                sb.Append ('>');
-            } else if (p is LSL_String) {
-                PrintParamString (sb, (string)(LSL_String)p);
-            } else if (p is LSL_Vector) {
-                LSL_Vector v = (LSL_Vector)p;
-                sb.Append ('<');
-                sb.Append (v.x);
-                sb.Append (',');
-                sb.Append (v.y);
-                sb.Append (',');
-                sb.Append (v.z);
-                sb.Append ('>');
-            } else if (p is string) {
-                PrintParamString (sb, (string)p);
-            } else {
-                sb.Append (p.ToString ());
-            }
-        }
-
-        public static void PrintParamString (StringBuilder sb, string p)
-        {
-            sb.Append ('"');
-            foreach (char c in p) {
-                if (c == '\b') {
-                    sb.Append ("\\b");
-                    continue;
-                }
-                if (c == '\n') {
-                    sb.Append ("\\n");
-                    continue;
-                }
-                if (c == '\r') {
-                    sb.Append ("\\r");
-                    continue;
-                }
-                if (c == '\t') {
-                    sb.Append ("\\t");
-                    continue;
-                }
-                if (c == '"') {
-                    sb.Append ("\\\"");
-                    continue;
-                }
-                if (c == '\\') {
-                    sb.Append ("\\\\");
-                    continue;
-                }
-                sb.Append (c);
-            }
-            sb.Append ('"');
-        }
-    }
-
-    /**
-     * @brief Code generators...
-     * @param scg = script we are generating code for
-     * @param result = type/location for result (type matches function definition)
-     * @param args = type/location of arguments (types match function definition)
-     */
-
-    public class TokenDeclInline_LLAbs : TokenDeclInline {
-        public TokenDeclInline_LLAbs (VarDict ifd)
-                : base (ifd, false, "llAbs(integer)", new TokenTypeInt (null)) { }
-
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel ("llAbstemp");
-
-            args[0].PushVal (scg, errorAt);
-            scg.ilGen.Emit (errorAt, OpCodes.Dup);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Bge_S, itsPosLabel);
-            scg.ilGen.Emit (errorAt, OpCodes.Neg);
-            scg.ilGen.MarkLabel (itsPosLabel);
-            result.Pop (scg, errorAt, retType);
-        }
-    }
-
-    public class TokenDeclInline_Math : TokenDeclInline {
-        private MethodInfo methInfo;
-
-        public TokenDeclInline_Math (VarDict ifd, string sig, string name, Type[] args)
-                : base (ifd, false, sig, new TokenTypeFloat (null))
-        {
-            methInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), name, args);
-        }
-
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            for (int i = 0; i < args.Length; i ++) {
-                args[i].PushVal (scg, errorAt, argDecl.types[i]);
-            }
-            scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
-            result.Pop (scg, errorAt, retType);
-        }
-    }
-
-    public class TokenDeclInline_LLRound : TokenDeclInline {
-
-        private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), "Round", 
-                new Type[] { typeof (double), typeof (MidpointRounding) });
-
-        public TokenDeclInline_LLRound (VarDict ifd)
-                : base (ifd, false, "llRound(float)", new TokenTypeInt (null)) { }
-
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            args[0].PushVal (scg, errorAt, new TokenTypeFloat (null));
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero);
-            scg.ilGen.Emit (errorAt, OpCodes.Call, roundMethInfo);
-            result.Pop (scg, errorAt, new TokenTypeFloat (null));
-        }
-    }
-
-    public class TokenDeclInline_GetFreeMemory : TokenDeclInline {
-        private static readonly MethodInfo getFreeMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapLeft", new Type[] { });
-
-        public TokenDeclInline_GetFreeMemory (VarDict ifd)
-                : base (ifd, false, "llGetFreeMemory()", new TokenTypeInt (null)) { }
-
-        // appears as llGetFreeMemory() in script source code
-        // but actually calls xmrHeapLeft()
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            scg.PushXMRInst ();
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getFreeMemMethInfo);
-            result.Pop (scg, errorAt, new TokenTypeInt (null));
-        }
-    }
-
-    public class TokenDeclInline_GetUsedMemory : TokenDeclInline {
-        private static readonly MethodInfo getUsedMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapUsed", new Type[] { });
-
-        public TokenDeclInline_GetUsedMemory (VarDict ifd)
-                : base (ifd, false, "llGetUsedMemory()", new TokenTypeInt (null)) { }
-
-        // appears as llGetUsedMemory() in script source code
-        // but actually calls xmrHeapUsed()
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            scg.PushXMRInst ();
-            scg.ilGen.Emit (errorAt, OpCodes.Call, getUsedMemMethInfo);
-            result.Pop (scg, errorAt, new TokenTypeInt (null));
-        }
-    }
-
-    /**
-     * @brief Generate code for the usual ll...() functions.
-     */
-    public class TokenDeclInline_BEApi : TokenDeclInline {
-//        private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod 
-//                (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) });
-
-//        private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod 
-//                (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) });
-
-        public bool doCheckRun;
-        private FieldInfo apiContextField;
-        private MethodInfo methInfo;
-
-        /**
-         * @brief Constructor
-         * @param ifd = dictionary to add the function to
-         * @param dcr = append a call to CheckRun()
-         * @param methInfo = ll...() method to be called
-         */
-        public TokenDeclInline_BEApi (VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf)
-                : base (ifd, dcr, methInfo)
-        {
-            this.methInfo = methInfo;
-            doCheckRun = dcr;
-            apiContextField = acf;
-        }
-
-        public override MethodInfo GetMethodInfo ()
-        {
-            return methInfo;
-        }
-
-        /**
-         * @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun().
-         * @param scg    = script being compiled
-         * @param result = where to place result (might be void)
-         * @param args   = script-visible arguments to pass to API function
-         */
-        public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-        {
-            if (isTaggedCallsCheckRun)
-            {                                                   // see if 'xmr' method that calls CheckRun() internally
-                new ScriptCodeGen.CallLabel (scg, errorAt);     // if so, put a call label immediately before it
-                                                                // .. so restoring the frame will jump immediately to the
-                                                                // .. call without re-executing any code before this
-            }
-            if (!methInfo.IsStatic)
-            {
-                scg.PushXMRInst ();                          // XMRInstanceSuperType pointer
-                if (apiContextField != null)                 // 'this' pointer for API function
-                    scg.ilGen.Emit (errorAt, OpCodes.Ldfld, apiContextField);
-                                                             
-            }
-            for (int i = 0; i < args.Length; i ++)             // push arguments, boxing/unboxing as needed
-                args[i].PushVal (scg, errorAt, argDecl.types[i]);
-
-            // this should not be needed
-//            if (methInfo.Name == "llParcelMediaQuery") {
-//                scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery);
-//            }
-            // this should not be needed
-//            if (methInfo.Name == "llParcelMediaCommandList") {
-//                scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList);
-//            }
-            if (methInfo.IsVirtual)                            // call API function
-                scg.ilGen.Emit (errorAt, OpCodes.Callvirt, methInfo);
-            else
-                scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
-
-            result.Pop (scg, errorAt, retType);                  // pop result, boxing/unboxing as needed
-            if (isTaggedCallsCheckRun)
-                scg.openCallLabel = null;
-
-            if (doCheckRun)
-                scg.EmitCallCheckRun (errorAt, false);       // maybe call CheckRun()
-        }
-    }
-}

+ 0 - 256
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjCode.cs

@@ -1,256 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.XMREngine;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public delegate void ScriptEventHandler (XMRInstAbstract instance);
-
-    /*
-     * This object represents the output of the compilation.
-     * Once the compilation is complete, its contents should be
-     * considered 'read-only', so it can be shared among multiple
-     * instances of the script.
-     *
-     * It gets created by ScriptCodeGen.
-     * It gets used by XMRInstance to create script instances.
-     */
-    public class ScriptObjCode
-    {
-        public string sourceHash;         // source text hash code
-
-        public XMRInstArSizes glblSizes = new XMRInstArSizes ();
-                                          // number of global variables of various types
-
-        public string[] stateNames;       // convert state number to corresponding string
-
-        public ScriptEventHandler[,] scriptEventHandlerTable;
-                                          // entrypoints to all event handler functions
-                                          // 1st subscript = state code number (0=default)
-                                          // 2nd subscript = event code number
-                                          // null entry means no handler defined for that state,event
-
-        public Dictionary<string, TokenDeclSDType> sdObjTypesName;
-                                          // all script-defined types by name
-        public TokenDeclSDType[] sdObjTypesIndx;
-                                          // all script-defined types by sdTypeIndex
-
-        public Dictionary<Type, string> sdDelTypes;
-                                          // all script-defined delegates (including anonymous)
-
-        public Dictionary<string, DynamicMethod> dynamicMethods;
-                                          // all dyanmic methods
-
-        public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
-                                          // method,iloffset -> source file,line,posn
-
-        public int refCount;              // used by engine to keep track of number of 
-                                          // instances that are using this object code
-
-        public Dictionary<string,Dictionary<int,string>> globalVarNames = new Dictionary<string,Dictionary<int,string>> ();
-
-        public DateTime fileDateUtc;
-        public int expiryDays = Int32.MaxValue;
-        public bool IsExpired ()
-        {
-            return (DateTime.UtcNow.Ticks - fileDateUtc.Ticks) / 10000000 / 86400 >= expiryDays;
-        }
-
-        /**
-         * @brief Fill in ScriptObjCode from an XMREngine object file.
-         *   'objFileReader' is a serialized form of the CIL code we generated
-         *   'asmFileWriter' is where we write the disassembly to (or null if not wanted)
-         *   'srcFileWriter' is where we write the decompilation to (or null if not wanted)
-         * Throws an exception if there is any error (theoretically).
-         */
-        public ScriptObjCode (BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
-        {
-            /*
-             * Check version number to make sure we know how to process file contents.
-             */
-            char[] ocm = objFileReader.ReadChars (ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
-            if (new String (ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC) {
-                throw new Exception ("not an XMR object file (bad magic)");
-            }
-            int cvv = objFileReader.ReadInt32 ();
-            if (cvv != ScriptCodeGen.COMPILED_VERSION_VALUE) {
-                throw new CVVMismatchException (cvv, ScriptCodeGen.COMPILED_VERSION_VALUE);
-            }
-
-            /*
-             * Fill in simple parts of scriptObjCode object.
-             */
-            sourceHash = objFileReader.ReadString ();
-            expiryDays = objFileReader.ReadInt32 ();
-            glblSizes.ReadFromFile (objFileReader);
-
-            int nStates = objFileReader.ReadInt32 ();
-
-            stateNames = new string[nStates];
-            for (int i = 0; i < nStates; i ++) {
-                stateNames[i] = objFileReader.ReadString ();
-                if (asmFileWriter != null) {
-                    asmFileWriter.WriteLine ("  state[{0}] = {1}", i, stateNames[i]);
-                }
-            }
-
-            if (asmFileWriter != null) {
-                glblSizes.WriteAsmFile (asmFileWriter, "numGbl");
-            }
-
-            string gblName;
-            while ((gblName = objFileReader.ReadString ()) != "") {
-                string gblType = objFileReader.ReadString ();
-                int gblIndex = objFileReader.ReadInt32 ();
-                Dictionary<int,string> names;
-                if (!globalVarNames.TryGetValue (gblType, out names)) {
-                    names = new Dictionary<int,string> ();
-                    globalVarNames.Add (gblType, names);
-                }
-                names.Add (gblIndex, gblName);
-                if (asmFileWriter != null) {
-                    asmFileWriter.WriteLine ("  {0} = {1}[{2}]", gblName, gblType, gblIndex);
-                }
-            }
-
-            /*
-             * Read in script-defined types.
-             */
-            sdObjTypesName = new Dictionary<string, TokenDeclSDType> ();
-            sdDelTypes = new Dictionary<Type, string> ();
-            int maxIndex = -1;
-            while ((gblName = objFileReader.ReadString ()) != "") {
-                TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile (sdObjTypesName, 
-                                                      gblName, objFileReader, asmFileWriter);
-                sdObjTypesName.Add (gblName, sdt);
-                if (maxIndex < sdt.sdTypeIndex) maxIndex = sdt.sdTypeIndex;
-                if (sdt is TokenDeclSDTypeDelegate) {
-                    sdDelTypes.Add (sdt.GetSysType (), gblName);
-                }
-            }
-            sdObjTypesIndx = new TokenDeclSDType[maxIndex+1];
-            foreach (TokenDeclSDType sdt in sdObjTypesName.Values) {
-                sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
-            }
-
-            /*
-             * Now fill in the methods (the hard part).
-             */
-            scriptEventHandlerTable = new ScriptEventHandler[nStates,(int)ScriptEventCode.Size];
-            dynamicMethods          = new Dictionary<string, DynamicMethod> ();
-            scriptSrcLocss          = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> ();
-
-            ObjectTokens objectTokens = null;
-            if (asmFileWriter != null) {
-                objectTokens = new OTDisassemble (this, asmFileWriter);
-            } else if (srcFileWriter != null) {
-                objectTokens = new OTDecompile (this, srcFileWriter);
-            }
-
-            try {
-                ScriptObjWriter.CreateObjCode (sdObjTypesName, objFileReader, this, objectTokens);
-            } finally {
-                if (objectTokens != null) objectTokens.Close ();
-            }
-
-            /*
-             * We enter all script event handler methods in the ScriptEventHandler table.
-             * They are named:  <statename> <eventname>
-             */
-            foreach (KeyValuePair<string, DynamicMethod> kvp in dynamicMethods) {
-                string methName = kvp.Key;
-                int i = methName.IndexOf (' ');
-                if (i < 0) continue;
-                string stateName = methName.Substring (0, i);
-                string eventName = methName.Substring (++ i);
-                int stateCode;
-                for (stateCode = stateNames.Length; -- stateCode >= 0;) {
-                    if (stateNames[stateCode] == stateName) break;
-                }
-                int eventCode = (int)Enum.Parse (typeof (ScriptEventCode), eventName);
-                scriptEventHandlerTable[stateCode,eventCode] = 
-                            (ScriptEventHandler)kvp.Value.CreateDelegate (typeof (ScriptEventHandler));
-            }
-
-            /*
-             * Fill in all script-defined class vtables.
-             */
-            foreach (TokenDeclSDType sdt in sdObjTypesIndx) {
-                if ((sdt != null) && (sdt is TokenDeclSDTypeClass)) {
-                    TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
-                    sdtc.FillVTables (this);
-                }
-            }
-        }
-
-        /**
-         * @brief Called once for every method found in objFileReader file.
-         *        It enters the method in the ScriptObjCode object table so it can be called.
-         */
-        public void EndMethod (DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
-        {
-            /*
-             * Save method object code pointer.
-             */
-            dynamicMethods.Add (method.Name, method);
-
-            /*
-             * Build and sort iloffset -> source code location array.
-             */
-            int n = srcLocs.Count;
-            KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
-            n = 0;
-            foreach (KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs) srcLocArray[n++] = kvp;
-            Array.Sort (srcLocArray, endMethodWrapper);
-
-            /*
-             * Save sorted array.
-             */
-            scriptSrcLocss.Add (method.Name, srcLocArray);
-        }
-
-        /**
-         * @brief Called once for every method found in objFileReader file.
-         *        It enters the method in the ScriptObjCode object table so it can be called.
-         */
-        private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper ();
-        private class EndMethodWrapper : System.Collections.IComparer {
-            public int Compare (object x, object y)
-            {
-                KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
-                KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
-                return kvpx.Key - kvpy.Key;
-            }
-        }
-    }
-}

+ 0 - 947
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptObjWriter.cs

@@ -1,947 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * @brief Wrapper class for ILGenerator.
- *        It writes the object code to a file and can then make real ILGenerator calls
- *        based on the file's contents.
- */
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public enum ScriptObjWriterCode : byte {
-        BegMethod, EndMethod, TheEnd,
-        DclLabel, DclLocal, DclMethod, MarkLabel,
-        EmitNull, EmitField, EmitLocal, EmitType, EmitLabel, EmitMethodExt, 
-        EmitMethodInt, EmitCtor, EmitDouble, EmitFloat, EmitInteger, EmitString,
-        EmitLabels,
-        BegExcBlk, BegCatBlk, BegFinBlk, EndExcBlk
-    }
-
-    public class ScriptObjWriter : ScriptMyILGen
-    {
-        private static Dictionary<short, OpCode> opCodes = PopulateOpCodes ();
-        private static Dictionary<string, Type> string2Type = PopulateS2T ();
-        private static Dictionary<Type, string> type2String = PopulateT2S ();
-
-        private static MethodInfo monoGetCurrentOffset = typeof (ILGenerator).GetMethod ("Mono_GetCurrentOffset",
-                        BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, 
-                        new Type[] { typeof (ILGenerator) }, null);
-
-        private static readonly OpCode[] opCodesLdcI4M1P8 = new OpCode[] {
-            OpCodes.Ldc_I4_M1, OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3, 
-            OpCodes.Ldc_I4_4,  OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8
-        };
-
-        private BinaryWriter objFileWriter;
-        private string lastErrorAtFile = "";
-        private int    lastErrorAtLine = 0;
-        private int    lastErrorAtPosn = 0;
-
-        private Dictionary<Type, string> sdTypesRev = new Dictionary<Type, string> ();
-        public int labelNumber = 0;
-        public int localNumber = 0;
-
-        private string _methName;
-        public string methName { get { return _methName; } }
-
-        public Type   retType;
-        public Type[] argTypes;
-
-        /**
-         * @brief Begin function declaration
-         * @param sdTypes    = script-defined types
-         * @param methName   = name of the method being declared, eg, "Verify(array,list,string)"
-         * @param retType    = its return value type
-         * @param argTypes[] = its argument types
-         * @param objFileWriter  = file to write its object code to
-         *
-         * After calling this function, the following functions should be called:
-         *    this.BegMethod ();
-         *      this.<as required> ();
-         *    this.EndMethod ();
-         *
-         * The design of this object is such that many constructors may be called,
-         * but once a BegMethod() is called for one of the objects, no method may
-         * called for any of the other objects until EndMethod() is called (or it 
-         * would break up the object stream for that method).  But we need to have
-         * many constructors possible so we get function headers at the beginning
-         * of the object file in case there are forward references to the functions.
-         */
-        public ScriptObjWriter (TokenScript tokenScript, string methName, Type retType, Type[] argTypes, string[] argNames, BinaryWriter objFileWriter)
-        {
-            this._methName     = methName;
-            this.retType       = retType;
-            this.argTypes      = argTypes;
-            this.objFileWriter = objFileWriter;
-
-            /*
-             * Build list that translates system-defined types to script defined types.
-             */
-            foreach (TokenDeclSDType sdt in tokenScript.sdSrcTypesValues) {
-                Type sys = sdt.GetSysType();
-                if (sys != null) sdTypesRev[sys] = sdt.longName.val;
-            }
-
-            /*
-             * This tells the reader to call 'new DynamicMethod()' to create
-             * the function header.  Then any forward reference calls to this
-             * method will have a MethodInfo struct to call.
-             */
-            objFileWriter.Write ((byte)ScriptObjWriterCode.DclMethod);
-            objFileWriter.Write (methName);
-            objFileWriter.Write (GetStrFromType (retType));
-
-            int nArgs = argTypes.Length;
-            objFileWriter.Write (nArgs);
-            for (int i = 0; i < nArgs; i ++) {
-                objFileWriter.Write (GetStrFromType (argTypes[i]));
-                objFileWriter.Write (argNames[i]);
-            }
-        }
-
-        /**
-         * @brief Begin outputting object code for the function
-         */
-        public void BegMethod ()
-        {
-            /*
-             * This tells the reader to call methodInfo.GetILGenerator()
-             * so it can start writing CIL code for the method.
-             */
-            objFileWriter.Write ((byte)ScriptObjWriterCode.BegMethod);
-            objFileWriter.Write (methName);
-        }
-
-        /**
-         * @brief End of object code for the function
-         */
-        public void EndMethod ()
-        {
-            /*
-             * This tells the reader that all code for the method has
-             * been written and so it will typically call CreateDelegate()
-             * to finalize the method and create an entrypoint.
-             */
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EndMethod);
-
-            objFileWriter = null;
-        }
-
-        /**
-         * @brief Declare a local variable for use by the function
-         */
-        public ScriptMyLocal DeclareLocal (Type type, string name)
-        {
-            ScriptMyLocal myLocal = new ScriptMyLocal ();
-            myLocal.type   = type;
-            myLocal.name   = name;
-            myLocal.number = localNumber ++;
-            myLocal.isReferenced = true;  // so ScriptCollector won't optimize references away
-            return DeclareLocal (myLocal);
-        }
-        public ScriptMyLocal DeclareLocal (ScriptMyLocal myLocal)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.DclLocal);
-            objFileWriter.Write (myLocal.number);
-            objFileWriter.Write (myLocal.name);
-            objFileWriter.Write (GetStrFromType (myLocal.type));
-            return myLocal;
-        }
-
-        /**
-         * @brief Define a label for use by the function
-         */
-        public ScriptMyLabel DefineLabel (string name)
-        {
-            ScriptMyLabel myLabel = new ScriptMyLabel ();
-            myLabel.name   = name;
-            myLabel.number = labelNumber ++;
-            return DefineLabel (myLabel);
-        }
-        public ScriptMyLabel DefineLabel (ScriptMyLabel myLabel)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.DclLabel);
-            objFileWriter.Write (myLabel.number);
-            objFileWriter.Write (myLabel.name);
-            return myLabel;
-        }
-
-        /**
-         * @brief try/catch blocks.
-         */
-        public void BeginExceptionBlock ()
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.BegExcBlk);
-        }
-
-        public void BeginCatchBlock (Type excType)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.BegCatBlk);
-            objFileWriter.Write (GetStrFromType (excType));
-        }
-
-        public void BeginFinallyBlock ()
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.BegFinBlk);
-        }
-
-        public void EndExceptionBlock ()
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EndExcBlk);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitNull);
-            WriteOpCode (errorAt, opcode);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, FieldInfo field)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitField);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (GetStrFromType (field.ReflectedType));
-            objFileWriter.Write (field.Name);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLocal);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (myLocal.number);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, Type type)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitType);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (GetStrFromType (type));
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabel);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (myLabel.number);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabels);
-            WriteOpCode (errorAt, opcode);
-            int nLabels = myLabels.Length;
-            objFileWriter.Write (nLabels);
-            for (int i = 0; i < nLabels; i ++) {
-                objFileWriter.Write (myLabels[i].number);
-            }
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method)
-        {
-            if (method == null) throw new ArgumentNullException ("method");
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodInt);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (method.methName);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, MethodInfo method)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodExt);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (method.Name);
-            objFileWriter.Write (GetStrFromType (method.ReflectedType));
-            ParameterInfo[] parms = method.GetParameters ();
-            int nArgs = parms.Length;
-            objFileWriter.Write (nArgs);
-            for (int i = 0; i < nArgs; i ++) {
-                objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
-            }
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitCtor);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (GetStrFromType (ctor.ReflectedType));
-            ParameterInfo[] parms = ctor.GetParameters ();
-            int nArgs = parms.Length;
-            objFileWriter.Write (nArgs);
-            for (int i = 0; i < nArgs; i ++) {
-                objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
-            }
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, double value)
-        {
-            if (opcode != OpCodes.Ldc_R8) {
-                throw new Exception ("bad opcode " + opcode.ToString ());
-            }
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitDouble);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (value);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, float value)
-        {
-            if (opcode != OpCodes.Ldc_R4) {
-                throw new Exception ("bad opcode " + opcode.ToString ());
-            }
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitFloat);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (value);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, int value)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitInteger);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (value);
-        }
-
-        public void Emit (Token errorAt, OpCode opcode, string value)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.EmitString);
-            WriteOpCode (errorAt, opcode);
-            objFileWriter.Write (value);
-        }
-
-        /**
-         * @brief Declare that the target of a label is the next instruction.
-         */
-        public void MarkLabel (ScriptMyLabel myLabel)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.MarkLabel);
-            objFileWriter.Write (myLabel.number);
-        }
-
-        /**
-         * @brief Write end-of-file marker to binary file.
-         */
-        public static void TheEnd (BinaryWriter objFileWriter)
-        {
-            objFileWriter.Write ((byte)ScriptObjWriterCode.TheEnd);
-        }
-
-        /**
-         * @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 ());
-                }
-            }
-        }
-
-        /**
-         * @brief Generate array to quickly translate OpCode.Value to full OpCode struct.
-         */
-        private static Dictionary<short, OpCode> PopulateOpCodes ()
-        {
-            Dictionary<short, OpCode> opCodeDict = new Dictionary<short, OpCode> ();
-            FieldInfo[] fields = typeof (OpCodes).GetFields ();
-            for (int i = 0; i < fields.Length; i ++) {
-                OpCode opcode = (OpCode)fields[i].GetValue (null);
-                opCodeDict.Add (opcode.Value, opcode);
-            }
-            return opCodeDict;
-        }
-
-        /**
-         * @brief Write opcode out to file.
-         */
-        private void WriteOpCode (Token errorAt, OpCode opcode)
-        {
-            if (errorAt == null) {
-                objFileWriter.Write ("");
-                objFileWriter.Write (lastErrorAtLine);
-                objFileWriter.Write (lastErrorAtPosn);
-            } else {
-                if (errorAt.file != lastErrorAtFile) {
-                    objFileWriter.Write (errorAt.file);
-                    lastErrorAtFile = errorAt.file;
-                } else {
-                    objFileWriter.Write ("");
-                }
-                objFileWriter.Write (errorAt.line);
-                objFileWriter.Write (errorAt.posn);
-                lastErrorAtLine = errorAt.line;
-                lastErrorAtPosn = errorAt.posn;
-            }
-            objFileWriter.Write (opcode.Value);
-        }
-
-        /**
-         * @brief Read opcode in from file.
-         */
-        private static OpCode ReadOpCode (BinaryReader objReader, ref string srcFile, ref int srcLine, ref int srcPosn)
-        {
-            string f = objReader.ReadString ();
-            if (f != "") srcFile = f;
-            srcLine = objReader.ReadInt32 ();
-            srcPosn = objReader.ReadInt32 ();
-
-            short value = objReader.ReadInt16 ();
-            return opCodes[value];
-        }
-
-        /**
-         * @brief Save an IL_offset -> source location translation entry
-         * @param srcLocs = saved entries for the current function
-         * @param offset = offset in IL object code for next instruction
-         * @param src{File,Line,Posn} = location in source file corresponding to opcode
-         * @returns with entry added to srcLocs
-         */
-        private static void SaveSrcLoc (Dictionary<int, ScriptSrcLoc> srcLocs, int offset, string srcFile, int srcLine, int srcPosn)
-        {
-            ScriptSrcLoc srcLoc = new ScriptSrcLoc ();
-            srcLoc.file = srcFile;
-            srcLoc.line = srcLine;
-            srcLoc.posn = srcPosn;
-            srcLocs[offset] = srcLoc;
-        }
-
-        /**
-         * @brief Create type<->string conversions.
-         *        Using Type.AssemblyQualifiedName is horribly inefficient
-         *        and all our types should be known.
-         */
-        private static Dictionary<string, Type> PopulateS2T ()
-        {
-            Dictionary<string, Type> s2t = new Dictionary<string, Type> ();
-
-            s2t.Add ("badcallx", typeof (ScriptBadCallNoException));
-            s2t.Add ("binopstr", typeof (BinOpStr));
-            s2t.Add ("bool",     typeof (bool));
-            s2t.Add ("char",     typeof (char));
-            s2t.Add ("delegate", typeof (Delegate));
-            s2t.Add ("delarr[]", typeof (Delegate[]));
-            s2t.Add ("double",   typeof (double));
-            s2t.Add ("exceptn",  typeof (Exception));
-            s2t.Add ("float",    typeof (float));
-            s2t.Add ("htlist",   typeof (HeapTrackerList));
-            s2t.Add ("htobject", typeof (HeapTrackerObject));
-            s2t.Add ("htstring", typeof (HeapTrackerString));
-            s2t.Add ("inlfunc",  typeof (CompValuInline));
-            s2t.Add ("int",      typeof (int));
-            s2t.Add ("int*",     typeof (int).MakeByRefType ());
-            s2t.Add ("intrlokd", typeof (System.Threading.Interlocked));
-            s2t.Add ("lslfloat", typeof (LSL_Float));
-            s2t.Add ("lslint",   typeof (LSL_Integer));
-            s2t.Add ("lsllist",  typeof (LSL_List));
-            s2t.Add ("lslrot",   typeof (LSL_Rotation));
-            s2t.Add ("lslstr",   typeof (LSL_String));
-            s2t.Add ("lslvec",   typeof (LSL_Vector));
-            s2t.Add ("math",     typeof (Math));
-            s2t.Add ("midround", typeof (MidpointRounding));
-            s2t.Add ("object",   typeof (object));
-            s2t.Add ("object*",  typeof (object).MakeByRefType ());
-            s2t.Add ("object[]", typeof (object[]));
-            s2t.Add ("scrbase",  typeof (ScriptBaseClass));
-            s2t.Add ("scrcode",  typeof (ScriptCodeGen));
-            s2t.Add ("sdtclobj", typeof (XMRSDTypeClObj));
-            s2t.Add ("string",   typeof (string));
-            s2t.Add ("typecast", typeof (TypeCast));
-            s2t.Add ("undstatx", typeof (ScriptUndefinedStateException));
-            s2t.Add ("void",     typeof (void));
-            s2t.Add ("xmrarray", typeof (XMR_Array));
-            s2t.Add ("xmrinst",  typeof (XMRInstAbstract));
-
-            return s2t;
-        }
-
-        private static Dictionary<Type, string> PopulateT2S ()
-        {
-            Dictionary<string, Type> s2t = PopulateS2T ();
-            Dictionary<Type, string> t2s = new Dictionary<Type, string> ();
-            foreach (KeyValuePair<string, Type> kvp in s2t) {
-                t2s.Add (kvp.Value, kvp.Key);
-            }
-            return t2s;
-        }
-
-        /**
-         * @brief Add to list of internally recognized types.
-         */
-        public static void DefineInternalType (string name, Type type)
-        {
-            if (!string2Type.ContainsKey(name))
-            {
-                string2Type.Add (name, type);
-                type2String.Add (type, name);
-            }
-        }
-
-        private string GetStrFromType (Type t)
-        {
-            string s = GetStrFromTypeWork (t);
-            return s;
-        }
-        private string GetStrFromTypeWork (Type t)
-        {
-            string s;
-
-            // internal fixed types like int and xmrarray etc
-            if (type2String.TryGetValue (t, out s)) return s;
-
-            // script-defined types
-            if (sdTypesRev.TryGetValue (t, out s)) return "sdt$" + s;
-
-            // inline function types
-            s = TokenDeclSDTypeDelegate.TryGetInlineName (t);
-            if (s != null) return s;
-
-            // last resort
-            return t.AssemblyQualifiedName;
-        }
-
-        private static Type GetTypeFromStr (Dictionary<string, TokenDeclSDType> sdTypes, string s)
-        {
-            Type t;
-
-            // internal fixed types like int and xmrarray etc
-            if (string2Type.TryGetValue (s, out t)) return t;
-
-            // script-defined types
-            if (s.StartsWith ("sdt$")) return sdTypes[s.Substring(4)].GetSysType ();
-
-            // inline function types
-            t = TokenDeclSDTypeDelegate.TryGetInlineSysType (s);
-            if (t != null) return t;
-
-            // last resort
-            return Type.GetType (s, true);
-        }
-    }
-
-    public class ScriptSrcLoc {
-        public string file;
-        public int line;
-        public int posn;
-    }
-}

+ 0 - 1724
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs

@@ -1,1724 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @brief Parse raw source file string into token list.
- *
- * Usage:
- *
- *    emsg = some function to output error messages to
- *    source = string containing entire source file
- *
- *    TokenBegin tokenBegin = TokenBegin.Construct (emsg, source);
- *
- *    tokenBegin = null: tokenizing error
- *                 else: first (dummy) token in file
- *                       the rest are chained by nextToken,prevToken
- *                       final token is always a (dummy) TokenEnd
- */
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine {
-
-    public delegate void TokenErrorMessage (Token token, string message);
-
-    /**
-     * @brief base class for all tokens
-     */
-    public class Token {
-        public static readonly int MAX_NAME_LEN = 255;
-        public static readonly int MAX_STRING_LEN = 4096;
-
-        public Token nextToken;
-        public Token prevToken;
-        public bool  nr2l;
-
-        // used for error message printing
-        public TokenErrorMessage emsg;
-        public string file = "";
-        public int line;
-        public int posn;
-        public Token copiedFrom;
-
-        /**
-         * @brief construct a token coming directly from a source file
-         * @param emsg = object that error messages get sent to
-         * @param file = source file name (or "" if none)
-         * @param line = source file line number
-         * @param posn = token's position within that source line
-         */
-        public Token (TokenErrorMessage emsg, string file, int line, int posn)
-        {
-            this.emsg = emsg;
-            this.file = file;
-            this.line = line;
-            this.posn = posn;
-        }
-
-        /**
-         * @brief construct a token with same error message parameters
-         * @param original = original token to create from
-         */
-        public Token (Token original)
-        {
-            if (original != null) {
-                this.emsg = original.emsg;
-                this.file = original.file;
-                this.line = original.line;
-                this.posn = original.posn;
-                this.nr2l = original.nr2l;
-            }
-        }
-
-        /**
-         * @brief output an error message associated with this token
-         *        sends the message to the token's error object
-         * @param message = error message string
-         */
-        public void ErrorMsg (string message)
-        {
-            if (emsg != null) {
-                emsg (this, message);
-            }
-        }
-
-        /*
-         * Generate a unique string (for use in CIL label names, etc)
-         */
-        public string Unique
-        {
-            get { return file + "_" + line + "_" + posn; }
-        }
-
-        /*
-         * Generate source location string (for use in error messages)
-         */
-        public string SrcLoc
-        {
-            get {
-                string loc = file + "(" + line + "," + posn + ")";
-                if (copiedFrom == null) return loc;
-                string fromLoc = copiedFrom.SrcLoc;
-                if (fromLoc.StartsWith (loc)) return fromLoc;
-                return loc + ":" + fromLoc;
-            }
-        }
-
-        /*
-         * Used in generic instantiation to copy token.
-         * Only valid for parsing tokens, not reduction tokens 
-         * because it is a shallow copy.
-         */
-        public Token CopyToken (Token src)
-        {
-            Token t = (Token)this.MemberwiseClone ();
-            t.file  = src.file;
-            t.line  = src.line;
-            t.posn  = src.posn;
-            t.copiedFrom = this;
-            return t;
-        }
-
-        /*
-         * Generate debugging string - should look like source code.
-         */
-        public virtual void DebString (StringBuilder sb)
-        {
-            sb.Append (this.ToString ());
-        }
-    }
-
-
-    /**
-     * @brief token that begins a source file
-     *        Along with TokenEnd, it keeps insertion/removal of intermediate tokens
-     *        simple as the intermediate tokens always have non-null nextToken,prevToken.
-     */
-    public class TokenBegin : Token {
-
-        public int expiryDays = Int32.MaxValue;  // has seen 'XMROption expiryDays;'
-
-        private class Options {
-            public bool arrays;         // has seen 'XMROption arrays;'
-            public bool advFlowCtl;     // has seen 'XMROption advFlowCtl;'
-            public bool tryCatch;       // has seen 'XMROption tryCatch;'
-            public bool objects;        // has seen 'XMROption objects;'
-            public bool chars;          // has seen 'XMROption chars;'
-            public bool noRightToLeft;  // has seen 'XMROption noRightToLeft;'
-            public bool dollarsigns;    // has seen 'XMROption dollarsigns;'
-        }
-
-        private bool youveAnError;      // there was some error tokenizing
-        private int bolIdx;             // index in 'source' at begining of current line
-        private int lineNo;             // current line in source file, starting at 0
-        private string filNam;          // current source file name
-        private string source;          // the whole script source code
-        private Token lastToken;        // last token created so far
-        private string cameFrom;        // where the source came from
-        private TextWriter saveSource;  // save copy of source here (or null)
-        private Options options = new Options ();
-
-        /**
-         * @brief convert a source file in the form of a string
-         *        to a list of raw tokens
-         * @param cameFrom = where the source came from
-         * @param emsg     = where to output messages to
-         * @param source   = whole source file contents
-         * @returns null: conversion error, message already output
-         *          else: list of tokens, starting with TokenBegin, ending with TokenEnd.
-         */
-        public static TokenBegin Construct (string cameFrom, TextWriter saveSource, TokenErrorMessage emsg, string source, out string sourceHash)
-        {
-            sourceHash = null;
-
-            /*
-             * Now do the tokenization.
-             */
-            TokenBegin tokenBegin = new TokenBegin (emsg, "", 0, 0);
-            tokenBegin.cameFrom   = cameFrom;
-            tokenBegin.saveSource = saveSource;
-            tokenBegin.lastToken  = tokenBegin;
-            tokenBegin.source     = source;
-            tokenBegin.filNam     = cameFrom;
-            if (saveSource != null) saveSource.WriteLine (source);
-            tokenBegin.Tokenize ();
-            if (tokenBegin.youveAnError) return null;
-            tokenBegin.AppendToken (new TokenEnd (emsg, tokenBegin.filNam, ++ tokenBegin.lineNo, 0));
-
-            /*
-             * Return source hash so caller can know if source changes.
-             */
-            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create ();
-            byte[] hashBytes = md5.ComputeHash (new TokenStream (tokenBegin));
-            int hashBytesLen = hashBytes.Length;
-            StringBuilder sb = new StringBuilder (hashBytesLen * 2);
-            for (int i = 0; i < hashBytesLen; i ++) {
-                sb.Append (hashBytes[i].ToString ("X2"));
-            }
-            sourceHash = sb.ToString ();
-            if (saveSource != null) {
-                saveSource.WriteLine ("");
-                saveSource.WriteLine ("********************************************************************************");
-                saveSource.WriteLine ("****  source hash: " + sourceHash);
-                saveSource.WriteLine ("********************************************************************************");
-            }
-
-            return tokenBegin;
-        }
-
-        private TokenBegin (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-
-        /*
-         * Stream consisting of all the tokens.
-         * Null delimeters between the tokens.
-         * Used for creating the source hash.
-         */
-        private class TokenStream : Stream {
-            private Token curTok;
-            private bool delim;
-            private byte[] curBuf;
-            private int curOfs;
-            private int curLen;
-
-            public TokenStream (Token t)
-            {
-                curTok = t;
-            }
-
-            public override bool CanRead  { get { return true;  } }
-            public override bool CanSeek  { get { return false; } }
-            public override bool CanWrite { get { return false; } }
-            public override long Length   { get { return 0; } }
-            public override long Position { get { return 0; } set { } }
-
-            public override void Write (byte[] buffer, int offset, int count) { }
-            public override void Flush () { }
-            public override long Seek (long offset, SeekOrigin origin) { return 0; }
-            public override void SetLength (long value) { }
-
-            public override int Read (byte[] buffer, int offset, int count)
-            {
-                int len, total;
-                for (total = 0; total < count; total += len) {
-                    while ((len = curLen - curOfs) <= 0) {
-                        if (curTok is TokenEnd) goto done;
-                        curTok = curTok.nextToken;
-                        if (curTok is TokenEnd) goto done;
-                        curBuf = System.Text.Encoding.UTF8.GetBytes (curTok.ToString ());
-                        curOfs = 0;
-                        curLen = curBuf.Length;
-                        delim  = true;
-                    }
-                    if (delim) {
-                        buffer[offset+total] = 0;
-                        delim = false;
-                        len   = 1;
-                    } else {
-                        if (len > count - total) len = count - total;
-                        Array.Copy (curBuf, curOfs, buffer, offset + total, len);
-                        curOfs += len;
-                    }
-                }
-              done:
-                return total;
-            }
-        }
-
-        /*
-         * Produces raw token stream: names, numbers, strings, keywords/delimeters.
-         * @param this.source = whole source file in one string
-         * @returns this.nextToken = filled in with tokens
-         *          this.youveAnError = true: some tokenizing error
-         *                             false: successful
-         */
-        private void Tokenize ()
-        {
-            bolIdx = 0;
-            lineNo = 0;
-            for (int i = 0; i < source.Length; i ++) {
-                char c = source[i];
-                if (c == '\n') {
-
-                    /*
-                     * Increment source line number and set char index of beg of next line.
-                     */
-                    lineNo ++;
-                    bolIdx = i + 1;
-
-                    /*
-                     * Check for '#' lineno filename newline
-                     * lineno is line number of next line in file
-                     * If found, save values and remove tokens from stream
-                     */
-                    if ((lastToken is TokenStr) &&
-                        (lastToken.prevToken is TokenInt) &&
-                        (lastToken.prevToken.prevToken is TokenKwHash)) {
-                        filNam = ((TokenStr)lastToken).val;
-                        lineNo = ((TokenInt)lastToken.prevToken).val;
-                        lastToken = lastToken.prevToken.prevToken.prevToken;
-                        lastToken.nextToken = null;
-                    }
-                    continue;
-                }
-
-                /*
-                 * Skip over whitespace.
-                 */
-                if (c <= ' ') continue;
-
-                /*
-                 * Skip over comments.
-                 */
-                if ((i + 2 <= source.Length) && source.Substring (i, 2).Equals ("//")) {
-                    while ((i < source.Length) && (source[i] != '\n')) i ++;
-                    lineNo ++;
-                    bolIdx = i + 1;
-                    continue;
-                }
-                if ((i + 2 <= source.Length) && (source.Substring (i, 2).Equals ("/*"))) {
-                    i += 2;
-                    while ((i + 1 < source.Length) && (((c = source[i]) != '*') || (source[i+1] != '/'))) {
-                        if (c == '\n') {
-                            lineNo ++;
-                            bolIdx = i + 1;
-                        }
-                        i ++;
-                    }
-                    i ++;
-                    continue;
-                }
-
-                /*
-                 * Check for numbers.
-                 */
-                if ((c >= '0') && (c <= '9')) {
-                    int j = TryParseFloat (i);
-                    if (j == 0) j = TryParseInt (i);
-                    i = -- j;
-                    continue;
-                }
-                if ((c == '.') && (source[i+1] >= '0') && (source[i+1] <= '9')) {
-                    int j = TryParseFloat (i);
-                    if (j > 0) i = -- j;
-                    continue;
-                }
-
-                /*
-                 * Check for quoted strings.
-                 */
-                if (c == '"') {
-                    StringBuilder sb = new StringBuilder ();
-                    bool backslash;
-                    int j;
-
-                    backslash = false;
-                    for (j = i; ++ j < source.Length;) {
-                        c = source[j];
-                        if (c == '\\' && !backslash) {
-                            backslash = true;
-                            continue;
-                        }
-                        if (c == '\n') {
-                            lineNo ++;
-                            bolIdx = j + 1;
-                        } else {
-                            if (!backslash && (c == '"')) break;
-                            if (backslash && (c == 'n')) c = '\n';
-                            if (backslash && (c == 't')) {
-                                sb.Append ("   ");
-                                c = ' ';
-                            }
-                        }
-                        backslash = false;
-                        sb.Append (c);
-                    }
-                    if (j - i > MAX_STRING_LEN) {
-                        TokenError (i, "string too long, max " + MAX_STRING_LEN);
-                    } else {
-                        AppendToken (new TokenStr (emsg, filNam, lineNo, i - bolIdx, sb.ToString ()));
-                    }
-                    i = j;
-                    continue;
-                }
-
-                /*
-                 * Check for quoted characters.
-                 */
-                if (c == '\'') {
-                    char cb = (char)0;
-                    bool backslash, overflow, underflow;
-                    int j;
-
-                    backslash = false;
-                    overflow  = false;
-                    underflow = true;
-                    for (j = i; ++ j < source.Length;) {
-                        c = source[j];
-                        if (c == '\\' && !backslash) {
-                            backslash = true;
-                            continue;
-                        }
-                        if (c == '\n') {
-                            lineNo ++;
-                            bolIdx = j + 1;
-                        } else {
-                            if (!backslash && (c == '\'')) break;
-                            if (backslash && (c == 'n')) c = '\n';
-                            if (backslash && (c == 't')) c = '\t';
-                        }
-                        backslash = false;
-                        overflow  = !underflow;
-                        underflow = false;
-                        cb = c;
-                    }
-                    if (underflow || overflow) {
-                        TokenError (i, "character must be exactly one character");
-                    } else {
-                        AppendToken (new TokenChar (emsg, filNam, lineNo, i - bolIdx, cb));
-                    }
-                    i = j;
-                    continue;
-                }
-
-                /*
-                 * Check for keywords/names.
-                 */
-                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c == '$' && options.dollarsigns)) {
-                    int j;
-
-                    for (j = i; ++ j < source.Length;) {
-                        c = source[j];
-                        if (c >= 'a' && c <= 'z') continue;
-                        if (c >= 'A' && c <= 'Z') continue;
-                        if (c >= '0' && c <= '9') continue;
-                        if (c == '$' && options.dollarsigns) continue;
-                        if (c != '_') break;
-                    }
-                    if (j - i > MAX_NAME_LEN) {
-                        TokenError (i, "name too long, max " + MAX_NAME_LEN);
-                    } else {
-                        string name = source.Substring (i, j - i);
-                        if (name == "quaternion") name = "rotation";  // see lslangtest1.lsl
-                        if (keywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)keywords[name].Invoke (args));
-                        } else if (options.arrays && arrayKeywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)arrayKeywords[name].Invoke (args));
-                        } else if (options.advFlowCtl && advFlowCtlKeywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)advFlowCtlKeywords[name].Invoke (args));
-                        } else if (options.tryCatch && tryCatchKeywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)tryCatchKeywords[name].Invoke (args));
-                        } else if (options.objects && objectsKeywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)objectsKeywords[name].Invoke (args));
-                        } else if (options.chars && charsKeywords.ContainsKey (name)) {
-                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
-                            AppendToken ((Token)charsKeywords[name].Invoke (args));
-                        } else {
-                            AppendToken (new TokenName (emsg, filNam, lineNo, i - bolIdx, name));
-                        }
-                    }
-                    i = -- j;
-                    continue;
-                }
-
-                /*
-                 * Check for option enables.
-                 */
-                if ((c == ';') && (lastToken is TokenName) && 
-                    (lastToken.prevToken is TokenName) && 
-                    (strcasecmp(((TokenName)lastToken.prevToken).val, "xmroption") == 0)) {
-                    string opt = ((TokenName)lastToken).val;
-                    if (strcasecmp (opt, "arrays") == 0) {
-                        options.arrays = true;
-                    } else if (strcasecmp (opt, "advflowctl") == 0) {
-                        options.advFlowCtl = true;
-                    } else if (strcasecmp (opt, "trycatch") == 0) {
-                        options.tryCatch = true;
-                    } else if (strcasecmp (opt, "objects") == 0) {
-                        options.objects = true;
-                    } else if (strcasecmp (opt, "chars") == 0) {
-                        options.chars = true;
-                    } else if (strcasecmp (opt, "norighttoleft") == 0) {
-                        options.noRightToLeft = true;
-                    } else if (strcasecmp (opt, "dollarsigns") == 0) {
-                        options.dollarsigns = true;
-                    } else {
-                        lastToken.ErrorMsg ("unknown XMROption");
-                    }
-                    lastToken = lastToken.prevToken.prevToken;
-                    lastToken.nextToken = null;
-                    continue;
-                }
-
-                /*
-                 * Handle 'xmroption' 'expirydays' numberofdays ';'
-                 */
-                if ((c == ';') && 
-                    (lastToken is TokenInt) && 
-                    (lastToken.prevToken is TokenName) && 
-                    (lastToken.prevToken.prevToken is TokenName) &&
-                    (strcasecmp(((TokenName)lastToken.prevToken.prevToken).val, "xmroption") == 0) && 
-                    (strcasecmp(((TokenName)lastToken.prevToken).val, "expirydays") == 0)) {
-                    expiryDays = ((TokenInt)lastToken).val;
-                    this.lastToken = lastToken.prevToken.prevToken.prevToken;
-                    this.lastToken.nextToken = null;
-                    continue;
-                }
-
-
-                /*
-                 * Handle 'xmroption' 'include' sourceurl ';'
-                 */
-                if ((c == ';') && 
-                    (lastToken is TokenStr) && 
-                    (lastToken.prevToken is TokenName) && 
-                    (lastToken.prevToken.prevToken is TokenName) &&
-                    (strcasecmp(((TokenName)lastToken.prevToken.prevToken).val, "xmroption") == 0) && 
-                    (strcasecmp(((TokenName)lastToken.prevToken).val, "include") == 0)) {
-
-                    string newURL      = ((TokenStr)lastToken).val;
-                    if (newURL == "") {
-                        lastToken.ErrorMsg ("empty URL string");
-                        continue;
-                    }
-                    string newCameFrom = CreateURL (this.cameFrom, newURL);
-                    string newSource   = ReadSourceFromURL (newCameFrom);
-
-                    this.lastToken     = lastToken.prevToken.prevToken.prevToken;
-                    this.lastToken.nextToken = null;
-
-                    if (newSource != null) {
-                        if (saveSource != null) {
-                            saveSource.WriteLine ("");
-                            saveSource.WriteLine ("********************************************************************************");
-                            saveSource.WriteLine ("****  include url: " + newCameFrom);
-                            saveSource.WriteLine ("********************************************************************************");
-                            saveSource.WriteLine (newSource);
-                        }
-
-                        string saveSourc    = this.source;
-                        string saveFilNam   = this.filNam;
-                        string saveCameFrom = this.cameFrom;
-                        int saveBolIdx      = this.bolIdx;
-                        int saveLineNo      = this.lineNo;
-                        Options saveOptions = this.options;
-                        this.source   = newSource;
-                        this.filNam   = newURL;
-                        this.cameFrom = newCameFrom;
-                        this.options  = new Options ();
-                        this.Tokenize ();
-                        this.source   = saveSourc;
-                        this.filNam   = saveFilNam;
-                        this.cameFrom = saveCameFrom;
-                        this.bolIdx   = saveBolIdx;
-                        this.lineNo   = saveLineNo;
-                        this.options  = saveOptions;
-                    }
-                    continue;
-                }
-
-                /*
-                 * Lastly, check for delimeters.
-                 */
-                {
-                    int j;
-                    int len = 0;
-
-                    for (j = 0; j < delims.Length; j ++) {
-                        len = delims[j].str.Length;
-                        if ((i + len <= source.Length) && (source.Substring (i, len).Equals (delims[j].str))) break;
-                    }
-                    if (j < delims.Length) {
-                        Object[] args = { emsg, filNam, lineNo, i - bolIdx };
-                        Token kwToken = (Token)delims[j].ctorInfo.Invoke (args);
-                        AppendToken (kwToken);
-                        i += -- len;
-                        continue;
-                    }
-                }
-
-                /*
-                 * Don't know what it is!
-                 */
-                TokenError (i, "unknown character '" + c + "'");
-            }
-        }
-
-        private static int strcasecmp (String s, String t)
-        {
-            return String.Compare(s,t,StringComparison.OrdinalIgnoreCase);
-        }
-
-        /**
-         * @brief try to parse a floating-point number from the source
-         * @param i = starting position within this.source of number
-         * @returns 0: not a floating point number, try something else
-         *       else: position in this.source of terminating character, ie, past number
-         *             TokenFloat appended to token list
-         *             or error message has been output
-         */
-        private int TryParseFloat (int i)
-        {
-            bool decimals, error, negexp, nulexp;
-            char c;
-            double f, f10;
-            int exponent, j, x, y;
-            ulong m, mantissa;
-
-            decimals = false;
-            error    = false;
-            exponent = 0;
-            mantissa = 0;
-            for (j = i; j < source.Length; j ++) {
-                c = source[j];
-                if ((c >= '0') && (c <= '9')) {
-                    m = mantissa * 10 + (ulong)(c - '0');
-                    if (m / 10 != mantissa) {
-                        if (!decimals) exponent ++;
-                    } else {
-                        mantissa = m;
-                        if (decimals) exponent --;
-                    }
-                    continue;
-                }
-                if (c == '.') {
-                    if (decimals) {
-                        TokenError (i, "more than one decimal point");
-                        return j;
-                    }
-                    decimals = true;
-                    continue;
-                }
-                if ((c == 'E') || (c == 'e')) {
-                    if (++ j >= source.Length) {
-                        TokenError (i, "floating exponent off end of source");
-                        return j;
-                    }
-                    c = source[j];
-                    negexp = (c == '-');
-                    if (negexp || (c == '+')) j ++;
-                    y = 0;
-                    nulexp = true;
-                    for (; j < source.Length; j ++) {
-                        c = source[j];
-                        if ((c < '0') || (c > '9')) break;
-                        x = y * 10 + (c - '0');
-                        if (x / 10 != y) {
-                            if (!error) TokenError (i, "floating exponent overflow");
-                            error = true;
-                        }
-                        y = x;
-                        nulexp = false;
-                    }
-                    if (nulexp) {
-                        TokenError (i, "bad or missing floating exponent");
-                        return j;
-                    }
-                    if (negexp) {
-                        x = exponent - y;
-                        if (x > exponent) {
-                            if (!error) TokenError (i, "floating exponent overflow");
-                            error = true;
-                        }
-                    } else {
-                        x = exponent + y;
-                        if (x < exponent) {
-                            if (!error) TokenError (i, "floating exponent overflow");
-                            error = true;
-                        }
-                    }
-                    exponent = x;
-                }
-                break;
-            }
-            if (!decimals) {
-                return 0;
-            }
-
-            f = mantissa;
-            if ((exponent != 0) && (mantissa != 0) && !error) {
-                f10 = 10.0;
-                if (exponent < 0) {
-                    exponent = -exponent;
-                    while (exponent > 0) {
-                        if ((exponent & 1) != 0) {
-                            f /= f10;
-                        }
-                        exponent /= 2;
-                        f10 *= f10;
-                    }
-                } else {
-                    while (exponent > 0) {
-                        if ((exponent & 1) != 0) {
-                            f *= f10;
-                        }
-                        exponent /= 2;
-                        f10 *= f10;
-                    }
-                }
-            }
-            if (!error) {
-                AppendToken (new TokenFloat (emsg, filNam, lineNo, i - bolIdx, f));
-            }
-            return j;
-        }
-
-        /**
-         * @brief try to parse an integer number from the source
-         * @param i = starting position within this.source of number
-         * @returns 0: not an integer number, try something else
-         *       else: position in this.source of terminating character, ie, past number
-         *             TokenInt appended to token list
-         *             or error message has been output
-         */
-        private int TryParseInt (int i)
-        {
-            bool error;
-            char c;
-            int j;
-            uint basse, m, mantissa;
-
-            basse    = 10;
-            error    = false;
-            mantissa = 0;
-            for (j = i; j < source.Length; j ++) {
-                c = source[j];
-                if ((c >= '0') && (c <= '9')) {
-                    m = mantissa * basse + (uint)(c - '0');
-                    if (m / basse != mantissa) {
-                        if (!error) TokenError (i, "integer overflow");
-                        error = true;
-                    }
-                    mantissa = m;
-                    continue;
-                }
-                if ((basse == 16) && ((c >= 'A') && (c <= 'F'))) {
-                    m = mantissa * basse + (uint)(c - 'A') + 10U;
-                    if (m / basse != mantissa) {
-                        if (!error) TokenError (i, "integer overflow");
-                        error = true;
-                    }
-                    mantissa = m;
-                    continue;
-                }
-                if ((basse == 16) && ((c >= 'a') && (c <= 'f'))) {
-                    m = mantissa * basse + (uint)(c - 'a') + 10U;
-                    if (m / basse != mantissa) {
-                        if (!error) TokenError (i, "integer overflow");
-                        error = true;
-                    }
-                    mantissa = m;
-                    continue;
-                }
-                if (((c == 'x') || (c == 'X')) && (mantissa == 0) && (basse == 10)) {
-                    basse = 16;
-                    continue;
-                }
-                break;
-            }
-            if (!error) {
-                AppendToken (new TokenInt (emsg, filNam, lineNo, i - bolIdx, (int)mantissa));
-            }
-            return j;
-        }
-
-        /**
-         * @brief append token on to end of list
-         * @param newToken = token to append
-         * @returns with token appended onto this.lastToken
-         */
-        private void AppendToken (Token newToken)
-        {
-            newToken.nextToken  = null;
-            newToken.prevToken  = lastToken;
-            newToken.nr2l       = this.options.noRightToLeft;
-            lastToken.nextToken = newToken;
-            lastToken           = newToken;
-        }
-
-        /**
-         * @brief print tokenizing error message
-         *        and remember that we've an error
-         * @param i = position within source file of the error
-         * @param message = error message text
-         * @returns with this.youveAnError set
-         */
-        private void TokenError (int i, string message)
-        {
-            Token temp = new Token (this.emsg, this.filNam, this.lineNo, i - this.bolIdx);
-            temp.ErrorMsg (message);
-            youveAnError = true;
-        }
-
-        /**
-         * @brief get a token's constructor
-         * @param tokenType = token's type
-         * @returns token's constructor
-         */
-        private static Type[] constrTypes = new Type[] {
-            typeof (TokenErrorMessage), typeof (string), typeof (int), typeof (int)
-        };
-
-        private static System.Reflection.ConstructorInfo GetTokenCtor (Type tokenType)
-        {
-            return tokenType.GetConstructor (constrTypes);
-        }
-
-        /**
-         * @brief delimeter table
-         */
-        private class Delim {
-            public string str;
-            public System.Reflection.ConstructorInfo ctorInfo;
-            public Delim (string str, Type type)
-            {
-                this.str = str;
-                ctorInfo = GetTokenCtor (type);
-            }
-        }
-
-        private static Delim[] delims = new Delim[] {
-            new Delim ("...", typeof (TokenKwDotDotDot)),
-            new Delim ("&&&", typeof (TokenKwAndAndAnd)),
-            new Delim ("|||", typeof (TokenKwOrOrOr)),
-            new Delim ("<<=", typeof (TokenKwAsnLSh)),
-            new Delim (">>=", typeof (TokenKwAsnRSh)),
-            new Delim ("<=",  typeof (TokenKwCmpLE)),
-            new Delim (">=",  typeof (TokenKwCmpGE)),
-            new Delim ("==",  typeof (TokenKwCmpEQ)),
-            new Delim ("!=",  typeof (TokenKwCmpNE)),
-            new Delim ("++",  typeof (TokenKwIncr)),
-            new Delim ("--",  typeof (TokenKwDecr)),
-            new Delim ("&&",  typeof (TokenKwAndAnd)),
-            new Delim ("||",  typeof (TokenKwOrOr)),
-            new Delim ("+=",  typeof (TokenKwAsnAdd)),
-            new Delim ("&=",  typeof (TokenKwAsnAnd)),
-            new Delim ("-=",  typeof (TokenKwAsnSub)),
-            new Delim ("*=",  typeof (TokenKwAsnMul)),
-            new Delim ("/=",  typeof (TokenKwAsnDiv)),
-            new Delim ("%=",  typeof (TokenKwAsnMod)),
-            new Delim ("|=",  typeof (TokenKwAsnOr)),
-            new Delim ("^=",  typeof (TokenKwAsnXor)),
-            new Delim ("<<",  typeof (TokenKwLSh)),
-            new Delim (">>",  typeof (TokenKwRSh)),
-            new Delim ("~",   typeof (TokenKwTilde)),
-            new Delim ("!",   typeof (TokenKwExclam)),
-            new Delim ("@",   typeof (TokenKwAt)),
-            new Delim ("%",   typeof (TokenKwMod)),
-            new Delim ("^",   typeof (TokenKwXor)),
-            new Delim ("&",   typeof (TokenKwAnd)),
-            new Delim ("*",   typeof (TokenKwMul)),
-            new Delim ("(",   typeof (TokenKwParOpen)),
-            new Delim (")",   typeof (TokenKwParClose)),
-            new Delim ("-",   typeof (TokenKwSub)),
-            new Delim ("+",   typeof (TokenKwAdd)),
-            new Delim ("=",   typeof (TokenKwAssign)),
-            new Delim ("{",   typeof (TokenKwBrcOpen)),
-            new Delim ("}",   typeof (TokenKwBrcClose)),
-            new Delim ("[",   typeof (TokenKwBrkOpen)),
-            new Delim ("]",   typeof (TokenKwBrkClose)),
-            new Delim (";",   typeof (TokenKwSemi)),
-            new Delim (":",   typeof (TokenKwColon)),
-            new Delim ("<",   typeof (TokenKwCmpLT)),
-            new Delim (">",   typeof (TokenKwCmpGT)),
-            new Delim (",",   typeof (TokenKwComma)),
-            new Delim (".",   typeof (TokenKwDot)),
-            new Delim ("?",   typeof (TokenKwQMark)),
-            new Delim ("/",   typeof (TokenKwDiv)),
-            new Delim ("|",   typeof (TokenKwOr)),
-            new Delim ("#",   typeof (TokenKwHash))
-        };
-
-        /**
-         * @brief keyword tables
-         *        The keyword tables translate a keyword string
-         *        to the corresponding token constructor.
-         */
-        private static Dictionary<string, System.Reflection.ConstructorInfo> keywords           = BuildKeywords ();
-        private static Dictionary<string, System.Reflection.ConstructorInfo> arrayKeywords      = BuildArrayKeywords ();
-        private static Dictionary<string, System.Reflection.ConstructorInfo> advFlowCtlKeywords = BuildAdvFlowCtlKeywords ();
-        private static Dictionary<string, System.Reflection.ConstructorInfo> tryCatchKeywords   = BuildTryCatchKeywords ();
-        private static Dictionary<string, System.Reflection.ConstructorInfo> objectsKeywords    = BuildObjectsKeywords ();
-        private static Dictionary<string, System.Reflection.ConstructorInfo> charsKeywords      = BuildCharsKeywords ();
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("default",  GetTokenCtor (typeof (TokenKwDefault)));
-            kws.Add ("do",       GetTokenCtor (typeof (TokenKwDo)));
-            kws.Add ("else",     GetTokenCtor (typeof (TokenKwElse)));
-            kws.Add ("float",    GetTokenCtor (typeof (TokenTypeFloat)));
-            kws.Add ("for",      GetTokenCtor (typeof (TokenKwFor)));
-            kws.Add ("if",       GetTokenCtor (typeof (TokenKwIf)));
-            kws.Add ("integer",  GetTokenCtor (typeof (TokenTypeInt)));
-            kws.Add ("list",     GetTokenCtor (typeof (TokenTypeList)));
-            kws.Add ("jump",     GetTokenCtor (typeof (TokenKwJump)));
-            kws.Add ("key",      GetTokenCtor (typeof (TokenTypeKey)));
-            kws.Add ("return",   GetTokenCtor (typeof (TokenKwRet)));
-            kws.Add ("rotation", GetTokenCtor (typeof (TokenTypeRot)));
-            kws.Add ("state",    GetTokenCtor (typeof (TokenKwState)));
-            kws.Add ("string",   GetTokenCtor (typeof (TokenTypeStr)));
-            kws.Add ("vector",   GetTokenCtor (typeof (TokenTypeVec)));
-            kws.Add ("while",    GetTokenCtor (typeof (TokenKwWhile)));
-
-            return kws;
-        }
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildArrayKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("array",   GetTokenCtor (typeof (TokenTypeArray)));
-            kws.Add ("foreach", GetTokenCtor (typeof (TokenKwForEach)));
-            kws.Add ("in",      GetTokenCtor (typeof (TokenKwIn)));
-            kws.Add ("is",      GetTokenCtor (typeof (TokenKwIs)));
-            kws.Add ("object",  GetTokenCtor (typeof (TokenTypeObject)));
-            kws.Add ("undef",   GetTokenCtor (typeof (TokenKwUndef)));
-
-            return kws;
-        }
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildAdvFlowCtlKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("break",    GetTokenCtor (typeof (TokenKwBreak)));
-            kws.Add ("case",     GetTokenCtor (typeof (TokenKwCase)));
-            kws.Add ("constant", GetTokenCtor (typeof (TokenKwConst)));
-            kws.Add ("continue", GetTokenCtor (typeof (TokenKwCont)));
-            kws.Add ("switch",   GetTokenCtor (typeof (TokenKwSwitch)));
-
-            return kws;
-        }
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildTryCatchKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("catch",     GetTokenCtor (typeof (TokenKwCatch)));
-            kws.Add ("exception", GetTokenCtor (typeof (TokenTypeExc)));
-            kws.Add ("finally",   GetTokenCtor (typeof (TokenKwFinally)));
-            kws.Add ("throw",     GetTokenCtor (typeof (TokenKwThrow)));
-            kws.Add ("try",       GetTokenCtor (typeof (TokenKwTry)));
-
-            return kws;
-        }
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildObjectsKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("abstract",    GetTokenCtor (typeof (TokenKwAbstract)));
-            kws.Add ("base",        GetTokenCtor (typeof (TokenKwBase)));
-            kws.Add ("class",       GetTokenCtor (typeof (TokenKwClass)));
-            kws.Add ("constructor", GetTokenCtor (typeof (TokenKwConstructor)));
-            kws.Add ("delegate",    GetTokenCtor (typeof (TokenKwDelegate)));
-            kws.Add ("destructor",  GetTokenCtor (typeof (TokenKwDestructor)));
-            kws.Add ("final",       GetTokenCtor (typeof (TokenKwFinal)));
-            kws.Add ("get",         GetTokenCtor (typeof (TokenKwGet)));
-            kws.Add ("interface",   GetTokenCtor (typeof (TokenKwInterface)));
-            kws.Add ("new",         GetTokenCtor (typeof (TokenKwNew)));
-            kws.Add ("override",    GetTokenCtor (typeof (TokenKwOverride)));
-            kws.Add ("partial",     GetTokenCtor (typeof (TokenKwPartial)));
-            kws.Add ("private",     GetTokenCtor (typeof (TokenKwPrivate)));
-            kws.Add ("protected",   GetTokenCtor (typeof (TokenKwProtected)));
-            kws.Add ("public",      GetTokenCtor (typeof (TokenKwPublic)));
-            kws.Add ("set",         GetTokenCtor (typeof (TokenKwSet)));
-            kws.Add ("static",      GetTokenCtor (typeof (TokenKwStatic)));
-            kws.Add ("this",        GetTokenCtor (typeof (TokenKwThis)));
-            kws.Add ("typedef",     GetTokenCtor (typeof (TokenKwTypedef)));
-            kws.Add ("virtual",     GetTokenCtor (typeof (TokenKwVirtual)));
-
-            return kws;
-        }
-
-        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildCharsKeywords ()
-        {
-            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo> ();
-
-            kws.Add ("char", GetTokenCtor (typeof (TokenTypeChar)));
-
-            return kws;
-        }
-
-        /**
-         * @brief Create a URL from a base URL and a relative string
-         * @param oldurl = base url string
-         * @param relurl = relative url
-         * @returns new url string
-         */
-        private static string CreateURL (string oldurl, string relurl)
-        {
-            if (relurl.IndexOf ("://") >= 0) return relurl;
-            StringBuilder newurl = new StringBuilder (oldurl.Length + relurl.Length);
-            if (relurl[0] == '/') {
-                // file:///oldname + /newname => file:///newname
-                // http://webserver.com/oldname + /newname => http://webserver.com/newname
-                int i = oldurl.IndexOf ("://") + 3;
-                int j = oldurl.IndexOf ('/', i);
-                if (j < 0) j = oldurl.Length;
-                newurl.Append (oldurl.Substring (0, j));
-                newurl.Append (relurl);
-            } else {
-                // file:///oldname + newname => file:///newname
-                // http://webserver.com/oldname + newname => http://webserver.com/newname
-                int i = oldurl.LastIndexOf ('/') + 1;
-                newurl.Append (oldurl.Substring (0, i));
-                newurl.Append (relurl);
-            }
-            return newurl.ToString ();
-        }
-
-        /**
-         * @brief Read source file from a webserver somewhere out there.
-         */
-        private const int MAX_INCLUDE_SIZE = 100000;
-        private Dictionary<string, string> scriptIncludes = new Dictionary<string, string> ();
-        private string ReadSourceFromURL (string url)
-        {
-            Stream stream = null;
-            StreamReader reader = null;
-
-            try {
-
-                /*
-                 * Get stream to read from webserver.
-                 */
-                stream = MMRWebRequest.MakeRequest ("GET", url, null, 0);
-                reader = new StreamReader (stream);
-
-                /*
-                 * Read file from stream.
-                 */
-                char[] buf = new char[4000];
-                int len = 0;
-                int total = 0;
-                List<char[]> fullBuffs = new List<char[]> ();
-                string signature = null;
-
-                while (true) {
-
-                    /*
-                     * Read a big chunk of characters.
-                     */
-                    len = reader.ReadBlock (buf, 0, buf.Length);
-
-                    /*
-                     * Signature is first line of the first chunk read and must be contained therein.
-                     * If an include file with the same signature has already been seen by this script, 
-                     * this include file is ignored.
-                     */
-                    if (signature == null) {
-                        signature   = new String (buf, 0, len);
-                        int siglen  = signature.IndexOf ('\n');
-                        if (siglen <= 0) {
-                            throw new Exception ("missing signature in first " + len + " characters: " + url);
-                        }
-                        signature   = signature.Substring (0, siglen);
-                        if (scriptIncludes.ContainsKey (signature)) return null;
-                        scriptIncludes.Add (signature, "");
-                    }
-
-                    /*
-                     * Signature is ok, stash full blocks away and keep reading.
-                     * If short read, means we have hit the end of the stream.
-                     */
-                    total += len;
-                    if (total > MAX_INCLUDE_SIZE) {
-                        throw new Exception ("script include exceeds maximum " + MAX_INCLUDE_SIZE + ": " + url);
-                    }
-                    if (len < buf.Length) break;
-                    fullBuffs.Add (buf);
-                    buf = new char[4000];
-                }
-
-                /*
-                 * Return the whole thing as one string.
-                 */
-                StringBuilder sb = new StringBuilder (total + url.Length + 20);
-                sb.Append ("# 1 \"");
-                sb.Append (url);
-                sb.Append ("\"\n");
-                foreach (char[] fullBuff in fullBuffs) {
-                    sb.Append (fullBuff);
-                }
-                sb.Append (buf, 0, len);
-                return sb.ToString ();
-            } finally {
-                     if (reader   != null) reader.Close ();
-                else if (stream   != null) stream.Close ();
-            }
-        }
-    }
-
-    /**
-     * @brief All output token types in addition to TokenBegin.
-     *        They are all sub-types of Token.
-     */
-
-    public class TokenChar : Token {
-        public char val;
-        public TokenChar (TokenErrorMessage emsg, string file, int line, int posn, char val) : base (emsg, file, line, posn)
-        {
-            this.val = val;
-        }
-        public TokenChar (Token original, char val) : base (original)
-        {
-            this.val = val;
-        }
-        public override string ToString ()
-        {
-            switch (val) {
-                case '\'': return "'\\''";
-                case '\\': return "'\\\\'";
-                case '\n': return "'\\n'";
-                case '\t': return "'\\t'";
-                default:   return "'" + val + "'";
-            }
-        }
-    }
-
-    public class TokenFloat : Token {
-        public double val;
-        public TokenFloat (TokenErrorMessage emsg, string file, int line, int posn, double val) : base (emsg, file, line, posn)
-        {
-            this.val = val;
-        }
-        public override string ToString ()
-        {
-            return val.ToString ();
-        }
-    }
-
-    public class TokenInt : Token {
-        public int val;
-        public TokenInt (TokenErrorMessage emsg, string file, int line, int posn, int val) : base (emsg, file, line, posn)
-        {
-            this.val = val;
-        }
-        public TokenInt (Token original, int val) : base (original)
-        {
-            this.val = val;
-        }
-        public override string ToString ()
-        {
-            return val.ToString ();
-        }
-    }
-
-    public class TokenName : Token {
-        public string val;
-        public TokenName (TokenErrorMessage emsg, string file, int line, int posn, string val) : base (emsg, file, line, posn)
-        {
-            this.val = val;
-        }
-        public TokenName (Token original, string val) : base (original)
-        {
-            this.val = val;
-        }
-        public override string ToString ()
-        {
-            return this.val;
-        }
-    }
-
-    public class TokenStr : Token {
-        public string val;
-        public TokenStr (TokenErrorMessage emsg, string file, int line, int posn, string val) : base (emsg, file, line, posn)
-        {
-            this.val = val;
-        }
-        public override string ToString ()
-        {
-            if ((val.IndexOf ('"') < 0) && 
-                (val.IndexOf ('\\') < 0) && 
-                (val.IndexOf ('\n') < 0) && 
-                (val.IndexOf ('\t') < 0)) return "\"" + val + "\"";
-
-            int len = val.Length;
-            StringBuilder sb = new StringBuilder (len * 2 + 2);
-            sb.Append ('"');
-            for (int i = 0; i < len; i ++) {
-                char c = val[i];
-                switch (c) {
-                    case '"': {
-                        sb.Append ('\\');
-                        sb.Append ('"');
-                        break;
-                    }
-                    case '\\': {
-                        sb.Append ('\\');
-                        sb.Append ('\\');
-                        break;
-                    }
-                    case '\n': {
-                        sb.Append ('\\');
-                        sb.Append ('n');
-                        break;
-                    }
-                    case '\t': {
-                        sb.Append ('\\');
-                        sb.Append ('t');
-                        break;
-                    }
-                    default: {
-                        sb.Append (c);
-                        break;
-                    }
-                }
-            }
-            return sb.ToString ();
-        }
-    }
-
-    /*
-     * This one marks the end-of-file.
-     */
-    public class TokenEnd : Token { public TokenEnd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } }
-
-    /*
-     * Various keywords and delimeters.
-     */
-    public delegate object TokenRValConstBinOpDelegate (object left, object right);
-    public delegate object TokenRValConstUnOpDelegate  (object right);
-
-    public class TokenKw : Token {
-        public TokenRValConstBinOpDelegate binOpConst;
-        public TokenRValConstUnOpDelegate  unOpConst;
-        public bool sdtClassOp;
-        public TokenKw (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenKw (Token original) : base (original)  { }
-    }
-
-    public class TokenKwDotDotDot : TokenKw { public TokenKwDotDotDot (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDotDotDot (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "..."; } }
-    public class TokenKwAndAndAnd : TokenKw { public TokenKwAndAndAnd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwAndAndAnd (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "&&&"; } }
-    public class TokenKwOrOrOr : TokenKw { public TokenKwOrOrOr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwOrOrOr (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "|||"; } }
-    public class TokenKwAsnLSh : TokenKw { public TokenKwAsnLSh (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnLSh (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "<<="; } }
-    public class TokenKwAsnRSh : TokenKw { public TokenKwAsnRSh (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnRSh (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return ">>="; } }
-    public class TokenKwCmpLE : TokenKw { public TokenKwCmpLE (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpLE (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "<="; } }
-    public class TokenKwCmpGE : TokenKw { public TokenKwCmpGE (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpGE (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return ">="; } }
-    public class TokenKwCmpEQ : TokenKw { public TokenKwCmpEQ (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpEQ (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "=="; } }
-    public class TokenKwCmpNE : TokenKw { public TokenKwCmpNE (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpNE (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "!="; } }
-    public class TokenKwIncr : TokenKw { public TokenKwIncr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwIncr (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "++"; } }
-    public class TokenKwDecr : TokenKw { public TokenKwDecr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDecr (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "--"; } }
-    public class TokenKwAndAnd : TokenKw { public TokenKwAndAnd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAndAnd (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "&&"; } }
-    public class TokenKwOrOr : TokenKw { public TokenKwOrOr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwOrOr (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "||"; } }
-    public class TokenKwAsnAdd : TokenKw { public TokenKwAsnAdd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnAdd (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "+="; } }
-    public class TokenKwAsnAnd : TokenKw { public TokenKwAsnAnd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnAnd (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "&="; } }
-    public class TokenKwAsnSub : TokenKw { public TokenKwAsnSub (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnSub (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "-="; } }
-    public class TokenKwAsnMul : TokenKw { public TokenKwAsnMul (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnMul (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "*="; } }
-    public class TokenKwAsnDiv : TokenKw { public TokenKwAsnDiv (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnDiv (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "/="; } }
-    public class TokenKwAsnMod : TokenKw { public TokenKwAsnMod (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnMod (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "%="; } }
-    public class TokenKwAsnOr : TokenKw { public TokenKwAsnOr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnOr (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "|="; } }
-    public class TokenKwAsnXor : TokenKw { public TokenKwAsnXor (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAsnXor (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "^="; } }
-    public class TokenKwLSh : TokenKw { public TokenKwLSh (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.LSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwLSh (Token original) : base (original) { binOpConst = TokenRValConstOps.LSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "<<"; } }
-    public class TokenKwRSh : TokenKw { public TokenKwRSh (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.RSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwRSh (Token original) : base (original) { binOpConst = TokenRValConstOps.RSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return ">>"; } }
-    public class TokenKwTilde : TokenKw { public TokenKwTilde (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Not; sdtClassOp = true; } public TokenKwTilde (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Not; sdtClassOp = true; } public override string ToString () { return "~"; } }
-    public class TokenKwExclam : TokenKw { public TokenKwExclam (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwExclam (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "!"; } }
-    public class TokenKwAt : TokenKw { public TokenKwAt (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwAt (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "@"; } }
-    public class TokenKwMod : TokenKw { public TokenKwMod (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Mod; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwMod (Token original) : base (original) { binOpConst = TokenRValConstOps.Mod; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "%"; } }
-    public class TokenKwXor : TokenKw { public TokenKwXor (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Xor; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwXor (Token original) : base (original) { binOpConst = TokenRValConstOps.Xor; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "^"; } }
-    public class TokenKwAnd : TokenKw { public TokenKwAnd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.And; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAnd (Token original) : base (original) { binOpConst = TokenRValConstOps.And; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "&"; } }
-    public class TokenKwMul : TokenKw { public TokenKwMul (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Mul; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwMul (Token original) : base (original) { binOpConst = TokenRValConstOps.Mul; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "*"; } }
-    public class TokenKwParOpen : TokenKw { public TokenKwParOpen (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwParOpen (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "("; } }
-    public class TokenKwParClose : TokenKw { public TokenKwParClose (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwParClose (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return ")"; } }
-    public class TokenKwSub : TokenKw { public TokenKwSub (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Sub; unOpConst = TokenRValConstOps.Neg; sdtClassOp = true; } public TokenKwSub (Token original) : base (original) { binOpConst = TokenRValConstOps.Sub; unOpConst = TokenRValConstOps.Neg; sdtClassOp = true; } public override string ToString () { return "-"; } }
-    public class TokenKwAdd : TokenKw { public TokenKwAdd (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Add; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwAdd (Token original) : base (original) { binOpConst = TokenRValConstOps.Add; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "+"; } }
-    public class TokenKwAssign : TokenKw { public TokenKwAssign (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwAssign (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "="; } }
-    public class TokenKwBrcOpen : TokenKw { public TokenKwBrcOpen (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBrcOpen (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "{"; } }
-    public class TokenKwBrcClose : TokenKw { public TokenKwBrcClose (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBrcClose (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "}"; } }
-    public class TokenKwBrkOpen : TokenKw { public TokenKwBrkOpen (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBrkOpen (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "["; } }
-    public class TokenKwBrkClose : TokenKw { public TokenKwBrkClose (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBrkClose (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "]"; } }
-    public class TokenKwSemi : TokenKw { public TokenKwSemi (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwSemi (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return ";"; } }
-    public class TokenKwColon : TokenKw { public TokenKwColon (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwColon (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return ":"; } }
-    public class TokenKwCmpLT : TokenKw { public TokenKwCmpLT (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpLT (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "<"; } }
-    public class TokenKwCmpGT : TokenKw { public TokenKwCmpGT (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwCmpGT (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return ">"; } }
-    public class TokenKwComma : TokenKw { public TokenKwComma (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwComma (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return ","; } }
-    public class TokenKwDot : TokenKw { public TokenKwDot (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDot (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "."; } }
-    public class TokenKwQMark : TokenKw { public TokenKwQMark (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwQMark (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "?"; } }
-    public class TokenKwDiv : TokenKw { public TokenKwDiv (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Div; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwDiv (Token original) : base (original) { binOpConst = TokenRValConstOps.Div; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "/"; } }
-    public class TokenKwOr : TokenKw { public TokenKwOr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Or; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public TokenKwOr (Token original) : base (original) { binOpConst = TokenRValConstOps.Or; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; } public override string ToString () { return "|"; } }
-    public class TokenKwHash : TokenKw { public TokenKwHash (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwHash (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "#"; } }
-
-    public class TokenKwAbstract : TokenKw { public TokenKwAbstract (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwAbstract (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "abstract"; } }
-    public class TokenKwBase : TokenKw { public TokenKwBase (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBase (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "base"; } }
-    public class TokenKwBreak : TokenKw { public TokenKwBreak (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwBreak (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "break"; } }
-    public class TokenKwCase : TokenKw { public TokenKwCase (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwCase (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "case"; } }
-    public class TokenKwCatch : TokenKw { public TokenKwCatch (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwCatch (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "catch"; } }
-    public class TokenKwClass : TokenKw { public TokenKwClass (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwClass (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "class"; } }
-    public class TokenKwConst : TokenKw { public TokenKwConst (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwConst (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "constant"; } }
-    public class TokenKwConstructor : TokenKw { public TokenKwConstructor (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwConstructor (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "constructor"; } }
-    public class TokenKwCont : TokenKw { public TokenKwCont (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwCont (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "continue"; } }
-    public class TokenKwDelegate : TokenKw { public TokenKwDelegate (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDelegate (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "delegate"; } }
-    public class TokenKwDefault : TokenKw { public TokenKwDefault (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDefault (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "default"; } }
-    public class TokenKwDestructor : TokenKw { public TokenKwDestructor (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDestructor (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "destructor"; } }
-    public class TokenKwDo : TokenKw { public TokenKwDo (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwDo (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "do"; } }
-    public class TokenKwElse : TokenKw { public TokenKwElse (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwElse (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "else"; } }
-    public class TokenKwFinal : TokenKw { public TokenKwFinal (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwFinal (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "final"; } }
-    public class TokenKwFinally : TokenKw { public TokenKwFinally (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwFinally (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "finally"; } }
-    public class TokenKwFor : TokenKw { public TokenKwFor (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwFor (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "for"; } }
-    public class TokenKwForEach : TokenKw { public TokenKwForEach (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwForEach (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "foreach"; } }
-    public class TokenKwGet : TokenKw { public TokenKwGet (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwGet (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "get"; } }
-    public class TokenKwIf : TokenKw { public TokenKwIf (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwIf (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "if"; } }
-    public class TokenKwIn : TokenKw { public TokenKwIn (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwIn (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "in"; } }
-    public class TokenKwInterface : TokenKw { public TokenKwInterface (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwInterface (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "interface"; } }
-    public class TokenKwIs : TokenKw { public TokenKwIs (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwIs (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "is"; } }
-    public class TokenKwJump : TokenKw { public TokenKwJump (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwJump (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "jump"; } }
-    public class TokenKwNew : TokenKw { public TokenKwNew (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwNew (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "new"; } }
-    public class TokenKwOverride : TokenKw { public TokenKwOverride (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwOverride (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "override"; } }
-    public class TokenKwPartial : TokenKw { public TokenKwPartial (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwPartial (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "partial"; } }
-    public class TokenKwPrivate : TokenKw { public TokenKwPrivate (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwPrivate (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "private"; } }
-    public class TokenKwProtected : TokenKw { public TokenKwProtected (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwProtected (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "protected"; } }
-    public class TokenKwPublic : TokenKw { public TokenKwPublic (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwPublic (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "public"; } }
-    public class TokenKwRet : TokenKw { public TokenKwRet (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwRet (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "return"; } }
-    public class TokenKwSet : TokenKw { public TokenKwSet (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwSet (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "set"; } }
-    public class TokenKwState : TokenKw { public TokenKwState (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwState (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "state"; } }
-    public class TokenKwStatic : TokenKw { public TokenKwStatic (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwStatic (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "static"; } }
-    public class TokenKwSwitch : TokenKw { public TokenKwSwitch (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwSwitch (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "switch"; } }
-    public class TokenKwThis : TokenKw { public TokenKwThis (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwThis (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "this"; } }
-    public class TokenKwThrow : TokenKw { public TokenKwThrow (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwThrow (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "throw"; } }
-    public class TokenKwTry : TokenKw { public TokenKwTry (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwTry (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "try"; } }
-    public class TokenKwTypedef : TokenKw { public TokenKwTypedef (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwTypedef (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "typedef"; } }
-    public class TokenKwUndef : TokenKw { public TokenKwUndef (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwUndef (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "undef"; } }
-    public class TokenKwVirtual : TokenKw { public TokenKwVirtual (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwVirtual (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "virtual"; } }
-    public class TokenKwWhile : TokenKw { public TokenKwWhile (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public TokenKwWhile (Token original) : base (original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; } public override string ToString () { return "while"; } }
-
-    /**
-     * @brief These static functions attempt to perform arithmetic on two constant
-     *        operands to generate the resultant constant.
-     *        Likewise for unary operators.
-     *
-     * @param left  = left-hand value
-     * @param right = right-hand value
-     * @returns null: not able to perform computation
-     *          else: resultant value object
-     *
-     * Note: it is ok for these to throw any exception (such as overflow or div-by-zero), 
-     *       and it will be treated as the 'not able to perform computation' case.
-     */
-    public class TokenRValConstOps {
-        public static object Null (object left, object right) { return null; }
-        public static object Div (object left, object right) { if ((left is int) && (right is int)) { return (int)left / (int)right; } if ((left is int) && (right is double)) { return (int)left / (double)right; } if ((left is double) && (right is int)) { return (double)left / (int)right; } if ((left is double) && (right is double)) { return (double)left / (double)right; } return null; }
-        public static object Mod (object left, object right) { if ((left is int) && (right is int)) { return (int)left % (int)right; } if ((left is int) && (right is double)) { return (int)left % (double)right; } if ((left is double) && (right is int)) { return (double)left % (int)right; } if ((left is double) && (right is double)) { return (double)left % (double)right; } return null; }
-        public static object Mul (object left, object right) { if ((left is int) && (right is int)) { return (int)left * (int)right; } if ((left is int) && (right is double)) { return (int)left * (double)right; } if ((left is double) && (right is int)) { return (double)left * (int)right; } if ((left is double) && (right is double)) { return (double)left * (double)right; } return null; }
-        public static object And (object left, object right) { if ((left is int) && (right is int)) { return (int)left & (int)right; } if ((left is int) && (right is double)) { return (int)left & (int)(double)right; } if ((left is double) && (right is int)) { return (int)(double)left & (int)right; } if ((left is double) && (right is double)) { return (int)(double)left & (int)(double)right; } return null; }
-        public static object LSh (object left, object right) { if ((left is int) && (right is int)) { return (int)left << (int)right; } if ((left is int) && (right is double)) { return (int)left << (int)(double)right; } if ((left is double) && (right is int)) { return (int)(double)left << (int)right; } if ((left is double) && (right is double)) { return (int)(double)left << (int)(double)right; } return null; }
-        public static object Or (object left, object right) { if ((left is int) && (right is int)) { return (int)left | (int)right; } if ((left is int) && (right is double)) { return (int)left | (int)(double)right; } if ((left is double) && (right is int)) { return (int)(double)left | (int)right; } if ((left is double) && (right is double)) { return (int)(double)left | (int)(double)right; } return null; }
-        public static object RSh (object left, object right) { if ((left is int) && (right is int)) { return (int)left >> (int)right; } if ((left is int) && (right is double)) { return (int)left >> (int)(double)right; } if ((left is double) && (right is int)) { return (int)(double)left >> (int)right; } if ((left is double) && (right is double)) { return (int)(double)left >> (int)(double)right; } return null; }
-        public static object Xor (object left, object right) { if ((left is int) && (right is int)) { return (int)left ^ (int)right; } if ((left is int) && (right is double)) { return (int)left ^ (int)(double)right; } if ((left is double) && (right is int)) { return (int)(double)left ^ (int)right; } if ((left is double) && (right is double)) { return (int)(double)left ^ (int)(double)right; } return null; }
-        public static object Add (object left, object right) { if ((left is char) && (right is int)) { return (char)((char)left + (int)right); } if ((left is double) && (right is double)) { return (double)left + (double)right; } if ((left is double) && (right is int)) { return (double)left + (int)right; } if ((left is double) && (right is string)) { return TypeCast.FloatToString((double)left) + (string)right; } if ((left is int) && (right is double)) { return (int)left + (double)right; } if ((left is int) && (right is int)) { return (int)left + (int)right; } if ((left is int) && (right is string)) { return TypeCast.IntegerToString((int)left) + (string)right; } if ((left is string) && (right is char)) { return (string)left + (char)right; } if ((left is string) && (right is double)) { return (string)left + TypeCast.FloatToString((double)right); } if ((left is string) && (right is int)) { return (string)left + TypeCast.IntegerToString ((int)right); } if ((left is string) && (right is string)) { return (string)left + (string)right; } return null; }
-        public static object Sub (object left, object right) { if ((left is char) && (right is int)) { return (char)((char)left - (int)right); } if ((left is int) && (right is int)) { return (int)left - (int)right; } if ((left is int) && (right is double)) { return (int)left - (double)right; } if ((left is double) && (right is int)) { return (double)left - (int)right; } if ((left is double) && (right is double)) { return (double)left - (double)right; } return null; }
-        public static object Null (object right) { return null; }
-        public static object Neg (object right) { if (right is int) { return - (int)right; } if (right is double) { return - (double)right; } return null; }
-        public static object Not (object right) { if (right is int) { return ~ (int)right; } return null; }
-    }
-
-    /*
-     * Various datatypes.
-     */
-    public abstract class TokenType : Token {
-
-        public TokenType (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenType (Token original) : base (original) { }
-
-        public static TokenType FromSysType (Token original, System.Type typ)
-        {
-            if (typ == typeof (LSL_List))     return new TokenTypeList      (original);
-            if (typ == typeof (LSL_Rotation)) return new TokenTypeRot       (original);
-            if (typ == typeof (void))         return new TokenTypeVoid      (original);
-            if (typ == typeof (LSL_Vector))   return new TokenTypeVec       (original);
-            if (typ == typeof (float))        return new TokenTypeFloat     (original);
-            if (typ == typeof (int))          return new TokenTypeInt       (original);
-            if (typ == typeof (string))       return new TokenTypeStr       (original);
-            if (typ == typeof (double))       return new TokenTypeFloat     (original);
-            if (typ == typeof (bool))         return new TokenTypeBool      (original);
-            if (typ == typeof (object))       return new TokenTypeObject    (original);
-            if (typ == typeof (XMR_Array))    return new TokenTypeArray     (original);
-            if (typ == typeof (LSL_Integer))  return new TokenTypeLSLInt    (original);
-            if (typ == typeof (LSL_Float))    return new TokenTypeLSLFloat  (original);
-            if (typ == typeof (LSL_String))   return new TokenTypeLSLString (original);
-            if (typ == typeof (char))         return new TokenTypeChar      (original);
-            if (typ == typeof (Exception))    return new TokenTypeExc       (original);
-
-            throw new Exception ("unknown script type " + typ.ToString ());
-        }
-
-        public static TokenType FromLSLType (Token original, string typ)
-        {
-            if (typ == "list")      return new TokenTypeList   (original);
-            if (typ == "rotation")  return new TokenTypeRot    (original);
-            if (typ == "vector")    return new TokenTypeVec    (original);
-            if (typ == "float")     return new TokenTypeFloat  (original);
-            if (typ == "integer")   return new TokenTypeInt    (original);
-            if (typ == "key")       return new TokenTypeKey    (original);
-            if (typ == "string")    return new TokenTypeStr    (original);
-            if (typ == "object")    return new TokenTypeObject (original);
-            if (typ == "array")     return new TokenTypeArray  (original);
-            if (typ == "bool")      return new TokenTypeBool   (original);
-            if (typ == "void")      return new TokenTypeVoid   (original);
-            if (typ == "char")      return new TokenTypeChar   (original);
-            if (typ == "exception") return new TokenTypeExc    (original);
-
-            throw new Exception ("unknown type " + typ);
-        }
-
-        /**
-         * @brief Estimate the number of bytes of memory taken by one of these
-         *        objects.  For objects with widely varying size, return the
-         *        smallest it can be.
-         */
-        public static int StaticSize (System.Type typ)
-        {
-            if (typ == typeof (LSL_List))     return  96;
-            if (typ == typeof (LSL_Rotation)) return  80;
-            if (typ == typeof (void))         return   0;
-            if (typ == typeof (LSL_Vector))   return  72;
-            if (typ == typeof (float))        return   8;
-            if (typ == typeof (int))          return   8;
-            if (typ == typeof (string))       return  40;
-            if (typ == typeof (double))       return   8;
-            if (typ == typeof (bool))         return   8;
-            if (typ == typeof (XMR_Array))    return  96;
-            if (typ == typeof (object))       return  32;
-            if (typ == typeof (char))         return   2;
-
-            if (typ == typeof (LSL_Integer))  return  32;
-            if (typ == typeof (LSL_Float))    return  32;
-            if (typ == typeof (LSL_String))   return  40;
-
-            throw new Exception ("unknown type " + typ.ToString ());
-        }
-
-        /**
-         * @brief Return the corresponding system type.
-         */
-        public abstract Type ToSysType ();
-
-        /**
-         * @brief Return the equivalent LSL wrapping type.
-         *
-         *  null: normal
-         *  else: LSL-style wrapping, ie, LSL_Integer, LSL_Float, LSL_String
-         *        ToSysType()=System.Int32;  lslWrapping=LSL_Integer
-         *        ToSysType()=System.Float;  lslWrapping=LSL_Float
-         *        ToSysType()=System.String; lslWrapping=LSL_String
-         */
-        public virtual Type ToLSLWrapType ()
-        {
-            return null;
-        }
-
-        /**
-         * @brief Assign slots in either the global variable arrays or the script-defined type instance arrays.
-         *        These only need to be implemented for script-visible types, ie, those that a script writer 
-         *        can actually define a variable as.
-         */
-        public virtual void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            throw new Exception ("not implemented for " + ToString () + " (" + GetType () + ")");
-        }
-
-        /**
-         * @brief Get heap tracking type.
-         *        null indicates there is no heap tracker for the type.
-         */
-        public virtual Type ToHeapTrackerType ()
-        {
-            return null;
-        }
-        public virtual ConstructorInfo GetHeapTrackerCtor ()
-        {
-            throw new ApplicationException("no GetHeapTrackerCtor for " + this.GetType());
-        }
-        public virtual void CallHeapTrackerPopMeth (Token errorAt, ScriptMyILGen ilGen)
-        {
-            throw new ApplicationException("no CallHeapTrackerPopMeth for " + this.GetType());
-        }
-        public virtual void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)
-        {
-            throw new ApplicationException("no CallHeapTrackerPushMeth for " + this.GetType());
-        }
-    }
-
-    public class TokenTypeArray : TokenType {
-        private static readonly FieldInfo iarArraysFieldInfo = typeof (XMRInstArrays).GetField ("iarArrays");
-
-        public TokenTypeArray (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeArray (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (XMR_Array); }
-        public override string ToString () { return "array"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarArraysFieldInfo;
-            declVar.vTableIndex = arSizes.iasArrays ++;
-        }
-    }
-    public class TokenTypeBool : TokenType {
-        public TokenTypeBool (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeBool (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (bool); }
-        public override string ToString () { return "bool"; }
-    }
-    public class TokenTypeChar : TokenType {
-        private static readonly FieldInfo iarCharsFieldInfo = typeof (XMRInstArrays).GetField ("iarChars");
-
-        public TokenTypeChar (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeChar (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (char); }
-        public override string ToString () { return "char"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarCharsFieldInfo;
-            declVar.vTableIndex = arSizes.iasChars ++;
-        }
-    }
-    public class TokenTypeExc : TokenType {
-        private static readonly FieldInfo iarObjectsFieldInfo = typeof (XMRInstArrays).GetField ("iarObjects");
-
-        public TokenTypeExc (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeExc (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (Exception); }
-        public override string ToString () { return "exception"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarObjectsFieldInfo;
-            declVar.vTableIndex = arSizes.iasObjects ++;
-        }
-    }
-    public class TokenTypeFloat : TokenType {
-        private static readonly FieldInfo iarFloatsFieldInfo = typeof (XMRInstArrays).GetField ("iarFloats");
-
-        public TokenTypeFloat (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeFloat (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (double); }
-        public override string ToString () { return "float"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarFloatsFieldInfo;
-            declVar.vTableIndex = arSizes.iasFloats ++;
-        }
-    }
-    public class TokenTypeInt : TokenType {
-        private static readonly FieldInfo iarIntegersFieldInfo = typeof (XMRInstArrays).GetField ("iarIntegers");
-
-        public TokenTypeInt (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeInt (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (int); }
-        public override string ToString () { return "integer"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarIntegersFieldInfo;
-            declVar.vTableIndex = arSizes.iasIntegers ++;
-        }
-    }
-    public class TokenTypeKey : TokenType {
-        private static readonly FieldInfo iarStringsFieldInfo = typeof (XMRInstArrays).GetField ("iarStrings");
-
-        public TokenTypeKey (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeKey (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (string); }
-        public override string ToString () { return "key"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarStringsFieldInfo;
-            declVar.vTableIndex = arSizes.iasStrings ++;
-        }
-    }
-    public class TokenTypeList : TokenType {
-        private static readonly FieldInfo iarListsFieldInfo = typeof (XMRInstArrays).GetField ("iarLists");
-        private static readonly ConstructorInfo htListCtor  = typeof (HeapTrackerList).GetConstructor (new Type [] { typeof (XMRInstAbstract) });
-
-        public TokenTypeList (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeList (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (LSL_List); }
-        public override string ToString () { return "list"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarListsFieldInfo;
-            declVar.vTableIndex = arSizes.iasLists ++;
-        }
-        public override Type ToHeapTrackerType () { return typeof (HeapTrackerList); }
-        public override ConstructorInfo GetHeapTrackerCtor () { return htListCtor; }
-        public override void CallHeapTrackerPopMeth (Token errorAt, ScriptMyILGen ilGen)   { HeapTrackerList.GenPop(errorAt, ilGen); }
-        public override void CallHeapTrackerPushMeth (Token errorAt, ScriptMyILGen ilGen)  { HeapTrackerList.GenPush(errorAt, ilGen); }
-    }
-    public class TokenTypeObject : TokenType {
-        private static readonly FieldInfo iarObjectsFieldInfo = typeof (XMRInstArrays).GetField ("iarObjects");
-        private static readonly ConstructorInfo htObjectCtor  = typeof (HeapTrackerObject).GetConstructor (new Type [] { typeof (XMRInstAbstract) });
-
-        public TokenTypeObject (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeObject (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (object); }
-        public override string ToString () { return "object"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarObjectsFieldInfo;
-            declVar.vTableIndex = arSizes.iasObjects ++;
-        }
-        public override Type ToHeapTrackerType () { return typeof (HeapTrackerObject); }
-        public override ConstructorInfo GetHeapTrackerCtor () { return htObjectCtor; }
-        public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)   { HeapTrackerObject.GenPop (errorAt, ilGen); }
-        public override void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)  { HeapTrackerObject.GenPush(errorAt, ilGen); }
-    }
-    public class TokenTypeRot : TokenType {
-        private static readonly FieldInfo iarRotationsFieldInfo = typeof (XMRInstArrays).GetField ("iarRotations");
-
-        public TokenTypeRot (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeRot (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (LSL_Rotation); }
-        public override string ToString () { return "rotation"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarRotationsFieldInfo;
-            declVar.vTableIndex = arSizes.iasRotations ++;
-        }
-    }
-    public class TokenTypeStr : TokenType {
-        private static readonly FieldInfo iarStringsFieldInfo = typeof (XMRInstArrays).GetField ("iarStrings");
-        private static readonly ConstructorInfo htStringCtor  = typeof (HeapTrackerString).GetConstructor (new Type [] { typeof (XMRInstAbstract) });
-
-        public TokenTypeStr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeStr (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (string); }
-        public override string ToString () { return "string"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarStringsFieldInfo;
-            declVar.vTableIndex = arSizes.iasStrings ++;
-        }
-        public override Type ToHeapTrackerType () { return typeof (HeapTrackerString); }
-        public override ConstructorInfo GetHeapTrackerCtor () { return htStringCtor; }
-        public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)   { HeapTrackerString.GenPop(errorAt, ilGen); }
-        public override void CallHeapTrackerPushMeth (Token errorAt, ScriptMyILGen ilGen)  { HeapTrackerString.GenPush(errorAt, ilGen); }
-    }
-    public class TokenTypeUndef : TokenType {  // for the 'undef' constant, ie, null object pointer
-        public TokenTypeUndef (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeUndef (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (object); }
-        public override string ToString () { return "undef"; }
-    }
-    public class TokenTypeVec : TokenType {
-        private static readonly FieldInfo iarVectorsFieldInfo = typeof (XMRInstArrays).GetField ("iarVectors");
-
-        public TokenTypeVec (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } 
-        public TokenTypeVec (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (LSL_Vector); }
-        public override string ToString () { return "vector"; }
-        public override void AssignVarSlot (TokenDeclVar declVar, XMRInstArSizes arSizes)
-        {
-            declVar.vTableArray = iarVectorsFieldInfo;
-            declVar.vTableIndex = arSizes.iasVectors ++;
-        }
-    }
-    public class TokenTypeVoid : TokenType {  // used only for function/method return types
-        public TokenTypeVoid (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeVoid (Token original) : base (original) { }
-        public override Type ToSysType () { return typeof (void); }
-        public override string ToString () { return "void"; }
-    }
-
-    public class TokenTypeLSLFloat : TokenTypeFloat {
-        public TokenTypeLSLFloat (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeLSLFloat (Token original) : base (original) { }
-        public override Type ToLSLWrapType () { return typeof (LSL_Float); }
-    }
-    public class TokenTypeLSLInt : TokenTypeInt {
-        public TokenTypeLSLInt (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeLSLInt (Token original) : base (original) { }
-        public override Type ToLSLWrapType () { return typeof (LSL_Integer); }
-    }
-    public class TokenTypeLSLKey : TokenTypeKey {
-        public TokenTypeLSLKey (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeLSLKey (Token original) : base (original) { }
-        public override Type ToLSLWrapType () { return typeof (LSL_Key); }
-    }
-    public class TokenTypeLSLString : TokenTypeStr {
-        public TokenTypeLSLString (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { }
-        public TokenTypeLSLString (Token original) : base (original) { }
-        public override Type ToLSLWrapType () { return typeof (LSL_String); }
-    }
-}

+ 0 - 819
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTypeCast.cs

@@ -1,819 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * @brief Generate script object code to perform type casting
- */
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-
-    public class TypeCast {
-        private delegate void CastDelegate (IScriptCodeGen scg, Token errorAt);
-
-        private static ConstructorInfo floatConstructorStringInfo   = typeof (LSL_Float).GetConstructor (new Type[] { typeof (string) });
-        private static ConstructorInfo integerConstructorStringInfo = typeof (LSL_Integer).GetConstructor (new Type[] { typeof (string) });
-        private static ConstructorInfo lslFloatConstructorInfo      = typeof (LSL_Float).GetConstructor (new Type[] { typeof (double) });
-        private static ConstructorInfo lslIntegerConstructorInfo    = typeof (LSL_Integer).GetConstructor (new Type[] { typeof (int) });
-        private static ConstructorInfo lslStringConstructorInfo     = typeof (LSL_String).GetConstructor (new Type[] { typeof (string) });
-        private static ConstructorInfo rotationConstrucorStringInfo = typeof (LSL_Rotation).GetConstructor (new Type[] { typeof (string) });
-        private static ConstructorInfo vectorConstrucorStringInfo   = typeof (LSL_Vector).GetConstructor (new Type[] { typeof (string) });
-        private static FieldInfo  lslFloatValueFieldInfo     = typeof (LSL_Float).GetField ("value");
-        private static FieldInfo  lslIntegerValueFieldInfo   = typeof (LSL_Integer).GetField ("value");
-        private static FieldInfo  lslStringValueFieldInfo    = typeof (LSL_String).GetField ("m_string");
-        private static FieldInfo  sdtcITableFieldInfo        = typeof (XMRSDTypeClObj).GetField ("sdtcITable");
-        private static MethodInfo boolToListMethodInfo       = typeof (TypeCast).GetMethod ("BoolToList",        new Type[] { typeof (bool) });
-        private static MethodInfo boolToStringMethodInfo     = typeof (TypeCast).GetMethod ("BoolToString",      new Type[] { typeof (bool) });
-        private static MethodInfo charToStringMethodInfo     = typeof (TypeCast).GetMethod ("CharToString",      new Type[] { typeof (char) });
-        private static MethodInfo excToStringMethodInfo      = typeof (TypeCast).GetMethod ("ExceptionToString", new Type[] { typeof (Exception), typeof (XMRInstAbstract) });
-        private static MethodInfo floatToStringMethodInfo    = typeof (TypeCast).GetMethod ("FloatToString",     new Type[] { typeof (double) });
-        private static MethodInfo intToStringMethodInfo      = typeof (TypeCast).GetMethod ("IntegerToString",   new Type[] { typeof (int) });
-        private static MethodInfo keyToBoolMethodInfo        = typeof (TypeCast).GetMethod ("KeyToBool",         new Type[] { typeof (string) });
-        private static MethodInfo listToBoolMethodInfo       = typeof (TypeCast).GetMethod ("ListToBool",        new Type[] { typeof (LSL_List) });
-        private static MethodInfo listToStringMethodInfo     = typeof (TypeCast).GetMethod ("ListToString",      new Type[] { typeof (LSL_List) });
-        private static MethodInfo objectToFloatMethodInfo    = typeof (TypeCast).GetMethod ("ObjectToFloat",     new Type[] { typeof (object) });
-        private static MethodInfo objectToIntegerMethodInfo  = typeof (TypeCast).GetMethod ("ObjectToInteger",   new Type[] { typeof (object) });
-        private static MethodInfo objectToListMethodInfo     = typeof (TypeCast).GetMethod ("ObjectToList",      new Type[] { typeof (object) });
-        private static MethodInfo objectToRotationMethodInfo = typeof (TypeCast).GetMethod ("ObjectToRotation",  new Type[] { typeof (object) });
-        private static MethodInfo objectToStringMethodInfo   = typeof (TypeCast).GetMethod ("ObjectToString",    new Type[] { typeof (object) });
-        private static MethodInfo objectToVectorMethodInfo   = typeof (TypeCast).GetMethod ("ObjectToVector",    new Type[] { typeof (object) });
-        private static MethodInfo rotationToBoolMethodInfo   = typeof (TypeCast).GetMethod ("RotationToBool",    new Type[] { typeof (LSL_Rotation) });
-        private static MethodInfo rotationToStringMethodInfo = typeof (TypeCast).GetMethod ("RotationToString",  new Type[] { typeof (LSL_Rotation) });
-        private static MethodInfo stringToBoolMethodInfo     = typeof (TypeCast).GetMethod ("StringToBool",      new Type[] { typeof (string) });
-        private static MethodInfo vectorToBoolMethodInfo     = typeof (TypeCast).GetMethod ("VectorToBool",      new Type[] { typeof (LSL_Vector) });
-        private static MethodInfo vectorToStringMethodInfo   = typeof (TypeCast).GetMethod ("VectorToString",    new Type[] { typeof (LSL_Vector) });
-        private static MethodInfo sdTypeClassCastClass2ClassMethodInfo = typeof (XMRSDTypeClObj).GetMethod ("CastClass2Class", new Type[] { typeof (object),     typeof (int) });
-        private static MethodInfo sdTypeClassCastIFace2ClassMethodInfo = typeof (XMRSDTypeClObj).GetMethod ("CastIFace2Class", new Type[] { typeof (Delegate[]), typeof (int) });
-        private static MethodInfo sdTypeClassCastObj2IFaceMethodInfo   = typeof (XMRSDTypeClObj).GetMethod ("CastObj2IFace",   new Type[] { typeof (object),     typeof (string) });
-        private static MethodInfo charToListMethodInfo       = typeof (TypeCast).GetMethod ("CharToList",     new Type[] { typeof (char) });
-        private static MethodInfo excToListMethodInfo        = typeof (TypeCast).GetMethod ("ExcToList",      new Type[] { typeof (Exception) });
-        private static MethodInfo vectorToListMethodInfo     = typeof (TypeCast).GetMethod ("VectorToList",   new Type[] { typeof (LSL_Vector) });
-        private static MethodInfo floatToListMethodInfo      = typeof (TypeCast).GetMethod ("FloatToList",    new Type[] { typeof (double) });
-        private static MethodInfo integerToListMethodInfo    = typeof (TypeCast).GetMethod ("IntegerToList",  new Type[] { typeof (int) });
-        private static MethodInfo rotationToListMethodInfo   = typeof (TypeCast).GetMethod ("RotationToList", new Type[] { typeof (LSL_Rotation) });
-        private static MethodInfo stringToListMethodInfo     = typeof (TypeCast).GetMethod ("StringToList",   new Type[] { typeof (string) });
-
-        /*
-         * List of all allowed type casts and how to perform the casting.
-         */
-        private static Dictionary<string, CastDelegate> legalTypeCasts = CreateLegalTypeCasts ();
-
-        /**
-         * @brief create a dictionary of legal type casts.
-         * Defines what EXPLICIT type casts are allowed in addition to the IMPLICIT ones.
-         * Key is of the form <oldtype> <newtype> for IMPLICIT casting.
-         * Key is of the form <oldtype>*<newtype> for EXPLICIT casting.
-         * Value is a delegate that generates code to perform the type cast.
-         */
-        private static Dictionary<string, CastDelegate> CreateLegalTypeCasts ()
-        {
-            Dictionary<string, CastDelegate> ltc = new Dictionary<string, CastDelegate> ();
-
-            // IMPLICIT type casts (a space is in middle of the key)
-            // EXPLICIT type casts (an * is in middle of the key)
-            // In general, only mark explicit if it might throw an exception
-            ltc.Add ("array object",     TypeCastArray2Object);
-            ltc.Add ("bool float",       TypeCastBool2Float);
-            ltc.Add ("bool integer",     TypeCastBool2Integer);
-            ltc.Add ("bool list",        TypeCastBool2List);
-            ltc.Add ("bool object",      TypeCastBool2Object);
-            ltc.Add ("bool string",      TypeCastBool2String);
-            ltc.Add ("char integer",     TypeCastChar2Integer);
-            ltc.Add ("char list",        TypeCastChar2List);
-            ltc.Add ("char object",      TypeCastChar2Object);
-            ltc.Add ("char string",      TypeCastChar2String);
-            ltc.Add ("exception list",   TypeCastExc2List);
-            ltc.Add ("exception object", TypeCastExc2Object);
-            ltc.Add ("exception string", TypeCastExc2String);
-            ltc.Add ("float bool",       TypeCastFloat2Bool);
-            ltc.Add ("float integer",    TypeCastFloat2Integer);
-            ltc.Add ("float list",       TypeCastFloat2List);
-            ltc.Add ("float object",     TypeCastFloat2Object);
-            ltc.Add ("float string",     TypeCastFloat2String);
-            ltc.Add ("integer bool",     TypeCastInteger2Bool);
-            ltc.Add ("integer char",     TypeCastInteger2Char);
-            ltc.Add ("integer float",    TypeCastInteger2Float);
-            ltc.Add ("integer list",     TypeCastInteger2List);
-            ltc.Add ("integer object",   TypeCastInteger2Object);
-            ltc.Add ("integer string",   TypeCastInteger2String);
-            ltc.Add ("list bool",        TypeCastList2Bool);
-            ltc.Add ("list object",      TypeCastList2Object);
-            ltc.Add ("list string",      TypeCastList2String);
-            ltc.Add ("object*array",     TypeCastObject2Array);
-            ltc.Add ("object*bool",      TypeCastObject2Bool);
-            ltc.Add ("object*char",      TypeCastObject2Char);
-            ltc.Add ("object*exception", TypeCastObject2Exc);
-            ltc.Add ("object*float",     TypeCastObject2Float);
-            ltc.Add ("object*integer",   TypeCastObject2Integer);
-            ltc.Add ("object*list",      TypeCastObject2List);
-            ltc.Add ("object*rotation",  TypeCastObject2Rotation);
-            ltc.Add ("object string",    TypeCastObject2String);
-            ltc.Add ("object*vector",    TypeCastObject2Vector);
-            ltc.Add ("rotation bool",    TypeCastRotation2Bool);
-            ltc.Add ("rotation list",    TypeCastRotation2List);
-            ltc.Add ("rotation object",  TypeCastRotation2Object);
-            ltc.Add ("rotation string",  TypeCastRotation2String);
-            ltc.Add ("string bool",      TypeCastString2Bool);
-            ltc.Add ("string float",     TypeCastString2Float);
-            ltc.Add ("string integer",   TypeCastString2Integer);
-            ltc.Add ("string list",      TypeCastString2List);
-            ltc.Add ("string object",    TypeCastString2Object);
-            ltc.Add ("string rotation",  TypeCastString2Rotation);
-            ltc.Add ("string vector",    TypeCastString2Vector);
-            ltc.Add ("vector bool",      TypeCastVector2Bool);
-            ltc.Add ("vector list",      TypeCastVector2List);
-            ltc.Add ("vector object",    TypeCastVector2Object);
-            ltc.Add ("vector string",    TypeCastVector2String);
-
-            return ltc;
-        }
-
-        /**
-         * @brief See if the given type can be cast to the other implicitly.
-         * @param dstType = type being cast to
-         * @param srcType = type being cast from
-         * @returns false: implicit cast not allowed
-         *           true: implicit cast allowed
-         */
-        public static bool IsAssignableFrom (TokenType dstType, TokenType srcType)
-        {
-            /*
-             * Do a 'dry run' of the casting operation, discarding any emits and not printing any errors.
-             * But if the casting tries to print error(s), return false.
-             * Otherwise assume the cast is allowed and return true.
-             */
-            SCGIAF scg = new SCGIAF ();
-            scg.ok = true;
-            scg._ilGen = migiaf;
-            CastTopOfStack (scg, null, srcType, dstType, false);
-            return scg.ok;
-        }
-
-        private struct SCGIAF : IScriptCodeGen {
-            public bool ok;
-            public ScriptMyILGen _ilGen;
-
-            // IScriptCodeGen
-            public ScriptMyILGen ilGen { get { return _ilGen; } }
-            public void ErrorMsg (Token token, string message) { ok = false; }
-            public void PushDefaultValue (TokenType type) { }
-            public void PushXMRInst () { }
-        }
-
-        private static readonly MIGIAF migiaf = new MIGIAF ();
-        private struct MIGIAF : ScriptMyILGen {
-            // ScriptMyILGen
-            public string methName { get { return null; } }
-            public ScriptMyLocal DeclareLocal (Type type, string name) { return null; }
-            public ScriptMyLabel DefineLabel (string name) { return null; }
-            public void BeginExceptionBlock () { }
-            public void BeginCatchBlock (Type excType) { }
-            public void BeginFinallyBlock () { }
-            public void EndExceptionBlock () { }
-            public void Emit (Token errorAt, OpCode opcode) { }
-            public void Emit (Token errorAt, OpCode opcode, FieldInfo field) { }
-            public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal) { }
-            public void Emit (Token errorAt, OpCode opcode, Type type) { }
-            public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel) { }
-            public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels) { }
-            public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method) { }
-            public void Emit (Token errorAt, OpCode opcode, MethodInfo method) { }
-            public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor) { }
-            public void Emit (Token errorAt, OpCode opcode, double value) { }
-            public void Emit (Token errorAt, OpCode opcode, float value) { }
-            public void Emit (Token errorAt, OpCode opcode, int value) { }
-            public void Emit (Token errorAt, OpCode opcode, string value) { }
-            public void MarkLabel (ScriptMyLabel myLabel) { }
-        }
-
-        /**
-         * @brief Emit code that converts the top stack item from 'oldType' to 'newType'
-         * @param scg = what script we are compiling
-         * @param errorAt = token used for source location for error messages
-         * @param oldType = type of item currently on the stack
-         * @param newType = type to convert it to
-         * @param explicitAllowed = false: only consider implicit casts
-         *                           true: consider both implicit and explicit casts
-         * @returns with code emitted for conversion (or error message output if not allowed, and stack left unchanged)
-         */
-        public static void CastTopOfStack (IScriptCodeGen scg, Token errorAt, TokenType oldType, TokenType newType, bool explicitAllowed)
-        {
-            CastDelegate castDelegate;
-            string oldString = oldType.ToString ();
-            string newString = newType.ToString ();
-
-            /*
-             * 'key' -> 'bool' is the only time we care about key being different than string.
-             */
-            if ((oldString == "key") && (newString == "bool")) {
-                LSLUnwrap (scg, errorAt, oldType);
-                scg.ilGen.Emit (errorAt, OpCodes.Call, keyToBoolMethodInfo);
-                LSLWrap (scg, errorAt, newType);
-                return;
-            }
-
-            /*
-             * Treat key and string as same type for all other type casts.
-             */
-            if (oldString == "key") oldString = "string";
-            if (newString == "key") newString = "string";
-
-            /*
-             * If the types are the same, there is no conceptual casting needed.
-             * However, there may be wraping/unwraping to/from the LSL wrappers.
-             */
-            if (oldString == newString) {
-                if (oldType.ToLSLWrapType () != newType.ToLSLWrapType ()) {
-                    LSLUnwrap (scg, errorAt, oldType);
-                    LSLWrap (scg, errorAt, newType);
-                }
-                return;
-            }
-
-            /*
-             * Script-defined classes can be cast up and down the tree.
-             */
-            if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeClass)) {
-                TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
-                TokenDeclSDTypeClass newSDTC = ((TokenTypeSDTypeClass)newType).decl;
-
-                // implicit cast allowed from leaf toward root
-                for (TokenDeclSDTypeClass sdtc = oldSDTC; sdtc != null; sdtc = sdtc.extends) {
-                    if (sdtc == newSDTC) return;
-                }
-
-                // explicit cast allowed from root toward leaf
-                for (TokenDeclSDTypeClass sdtc = newSDTC; sdtc != null; sdtc = sdtc.extends) {
-                    if (sdtc == oldSDTC) {
-                        ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
-                        scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, newSDTC.sdTypeIndex);
-                        scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
-                        return;
-                    }
-                }
-
-                // not on same branch
-                goto illcast;
-            }
-
-            /*
-             * One script-defined interface type cannot be cast to another script-defined interface type, 
-             * unless the old interface declares that it implements the new interface.  That proves that 
-             * the underlying object, no matter what type, implements the new interface.
-             */
-            if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeInterface)) {
-                TokenDeclSDTypeInterface oldDecl = ((TokenTypeSDTypeInterface)oldType).decl;
-                TokenDeclSDTypeInterface newDecl = ((TokenTypeSDTypeInterface)newType).decl;
-                if (!oldDecl.Implements (newDecl)) goto illcast;
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, newType.ToString ());
-                scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
-                return;
-            }
-
-            /*
-             * A script-defined class type can be implicitly cast to a script-defined interface type that it 
-             * implements.  The result is an array of delegates that give the class's implementation of the 
-             * various methods defined by the interface.
-             */
-            if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeInterface)) {
-                TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
-                int intfIndex;
-                if (!oldSDTC.intfIndices.TryGetValue (newType.ToString (), out intfIndex)) goto illcast;
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, sdtcITableFieldInfo);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, intfIndex);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (Delegate[]));
-                return;
-            }
-
-            /*
-             * A script-defined interface type can be explicitly cast to a script-defined class type by 
-             * extracting the Target property from element 0 of the delegate array that is the interface
-             * object and making sure it casts to the correct script-defined class type.
-             *
-             * But then only if the class type implements the interface type.
-             */
-            if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeClass)) {
-                TokenTypeSDTypeInterface oldSDTI = (TokenTypeSDTypeInterface)oldType;
-                TokenTypeSDTypeClass     newSDTC = (TokenTypeSDTypeClass)    newType;
-
-                if (!newSDTC.decl.CanCastToIntf (oldSDTI.decl)) goto illcast;
-
-                ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, newSDTC.decl.sdTypeIndex);
-                scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastIFace2ClassMethodInfo);
-                return;
-            }
-
-            /*
-             * A script-defined interface type can be implicitly cast to object.
-             */
-            if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeObject)) {
-                return;
-            }
-
-            /*
-             * An object can be explicitly cast to a script-defined interface.
-             */
-            if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeInterface)) {
-                ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, newString);
-                scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
-                return;
-            }
-
-            /*
-             * Cast to void is always allowed, such as discarding value from 'i++' or function return value.
-             */
-            if (newType is TokenTypeVoid) {
-                scg.ilGen.Emit (errorAt, OpCodes.Pop);
-                return;
-            }
-
-            /*
-             * Cast from undef to object or script-defined type is always allowed.
-             */
-            if ((oldType is TokenTypeUndef) && 
-                ((newType is TokenTypeObject) || 
-                 (newType is TokenTypeSDTypeClass) || 
-                 (newType is TokenTypeSDTypeInterface))) {
-                return;
-            }
-
-            /*
-             * Script-defined classes can be implicitly cast to objects.
-             */
-            if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeObject)) {
-                return;
-            }
-
-            /*
-             * Script-defined classes can be explicitly cast from objects and other script-defined classes.
-             * Note that we must manually check that it is the correct SDTypeClass however because as far as 
-             * mono is concerned, all SDTypeClass's are the same.
-             */
-            if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeClass)) {
-                ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, ((TokenTypeSDTypeClass)newType).decl.sdTypeIndex);
-                scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
-                return;
-            }
-
-            /*
-             * Delegates can be implicitly cast to/from objects.
-             */
-            if ((oldType is TokenTypeSDTypeDelegate) && (newType is TokenTypeObject)) {
-                return;
-            }
-            if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeDelegate)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, newType.ToSysType ());
-                return;
-            }
-
-            /*
-             * Some actual conversion is needed, see if it is in table of legal casts.
-             */
-            string key = oldString + " " + newString;
-            if (!legalTypeCasts.TryGetValue (key, out castDelegate)) {
-                key = oldString + "*" + newString;
-                if (!legalTypeCasts.TryGetValue (key, out castDelegate)) goto illcast;
-                ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
-            }
-
-            /*
-             * Ok, output cast.  But make sure it is in native form without any LSL wrapping
-             * before passing to our casting routine.  Then if caller is expecting an LSL-
-             * wrapped value on the stack upon return, wrap it up after our casting.
-             */
-            LSLUnwrap (scg, errorAt, oldType);
-            castDelegate (scg, errorAt);
-            LSLWrap (scg, errorAt, newType);
-            return;
-
-        illcast:
-            scg.ErrorMsg (errorAt, "illegal to cast from " + oldString + " to " + newString);
-            if (!(oldType is TokenTypeVoid)) scg.ilGen.Emit (errorAt, OpCodes.Pop);
-            scg.PushDefaultValue (newType);
-        }
-        private static void ExplCheck (IScriptCodeGen scg, Token errorAt, bool explicitAllowed, string oldString, string newString)
-        {
-            if (!explicitAllowed) {
-                scg.ErrorMsg (errorAt, "must explicitly cast from " + oldString + " to " + newString);
-            }
-        }
-
-        /**
-         * @brief If value on the stack is an LSL-style wrapped value, unwrap it.
-         */
-        public static void LSLUnwrap (IScriptCodeGen scg, Token errorAt, TokenType type)
-        {
-            if (type.ToLSLWrapType () == typeof (LSL_Float)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
-            }
-            if (type.ToLSLWrapType () == typeof (LSL_Integer)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
-            }
-            if (type.ToLSLWrapType () == typeof (LSL_String)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslStringValueFieldInfo);
-            }
-        }
-
-        /**
-         * @brief If caller wants the unwrapped value on stack wrapped LSL-style, wrap it.
-         */
-        private static void LSLWrap (IScriptCodeGen scg, Token errorAt, TokenType type)
-        {
-            if (type.ToLSLWrapType () == typeof (LSL_Float)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslFloatConstructorInfo);
-            }
-            if (type.ToLSLWrapType () == typeof (LSL_Integer)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslIntegerConstructorInfo);
-            }
-            if (type.ToLSLWrapType () == typeof (LSL_String)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslStringConstructorInfo);
-            }
-        }
-
-        /**
-         * @brief These routines output code to perform casting.
-         *        They can assume there are no LSL wrapped values on input
-         *        and they should not output an LSL wrapped value.
-         */
-        private static void TypeCastArray2Object (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastBool2Float (IScriptCodeGen scg, Token errorAt)
-        {
-            if (typeof (double) == typeof (float)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Conv_R4);
-            } else if (typeof (double) == typeof (double)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Conv_R8);
-            } else {
-                throw new Exception ("unknown type");
-            }
-        }
-        private static void TypeCastBool2Integer (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastBool2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (bool));
-        }
-        private static void TypeCastChar2Integer (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastChar2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, charToListMethodInfo);
-        }
-        private static void TypeCastChar2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (char));
-        }
-        private static void TypeCastChar2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, charToStringMethodInfo);
-        }
-        private static void TypeCastExc2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, excToListMethodInfo);
-        }
-        private static void TypeCastExc2Object (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastExc2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.PushXMRInst ();
-            scg.ilGen.Emit (errorAt, OpCodes.Call, excToStringMethodInfo);
-        }
-        private static void TypeCastFloat2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_R4, 0.0f);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-        }
-        private static void TypeCastFloat2Integer (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Conv_I4);
-        }
-        private static void TypeCastFloat2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (double));
-        }
-        private static void TypeCastInteger2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
-            scg.ilGen.Emit (errorAt, OpCodes.Ceq);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
-            scg.ilGen.Emit (errorAt, OpCodes.Xor);
-        }
-        private static void TypeCastInteger2Char (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastInteger2Float (IScriptCodeGen scg, Token errorAt)
-        {
-            if (typeof (double) == typeof (float)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Conv_R4);
-            } else if (typeof (double) == typeof (double)) {
-                scg.ilGen.Emit (errorAt, OpCodes.Conv_R8);
-            } else {
-                throw new Exception ("unknown type");
-            }
-        }
-        private static void TypeCastInteger2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (int));
-        }
-        private static void TypeCastList2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, listToBoolMethodInfo);
-        }
-        private static void TypeCastList2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            if (typeof (LSL_List).IsValueType) {
-                scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_List));
-            }
-        }
-        private static void TypeCastObject2Array (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (XMR_Array));
-        }
-        private static void TypeCastObject2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Unbox_Any, typeof (bool));
-        }
-        private static void TypeCastObject2Char (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Unbox_Any, typeof (char));
-        }
-        private static void TypeCastObject2Exc (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (Exception));
-        }
-        private static void TypeCastObject2Float (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, objectToFloatMethodInfo);
-        }
-        private static void TypeCastObject2Integer (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, objectToIntegerMethodInfo);
-        }
-        private static void TypeCastObject2List (IScriptCodeGen scg, Token errorAt)
-        {
-            if (typeof (LSL_List).IsValueType) {
-                scg.ilGen.Emit (errorAt, OpCodes.Call, objectToListMethodInfo);
-            } else {
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (LSL_List));
-            }
-        }
-        private static void TypeCastObject2Rotation (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, objectToRotationMethodInfo);
-        }
-        private static void TypeCastObject2Vector (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, objectToVectorMethodInfo);
-        }
-        private static void TypeCastRotation2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToBoolMethodInfo);
-        }
-        private static void TypeCastRotation2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_Rotation));
-        }
-        private static void TypeCastString2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringToBoolMethodInfo);
-        }
-        private static void TypeCastString2Object (IScriptCodeGen scg, Token errorAt)
-        {
-        }
-        private static void TypeCastString2Rotation (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, rotationConstrucorStringInfo);
-        }
-        private static void TypeCastString2Vector (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, vectorConstrucorStringInfo);
-        }
-        private static void TypeCastVector2Bool (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToBoolMethodInfo);
-        }
-        private static void TypeCastVector2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToListMethodInfo);
-        }
-        private static void TypeCastVector2Object (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_Vector));
-        }
-        private static void TypeCastBool2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, boolToListMethodInfo);
-        }
-        private static void TypeCastBool2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, boolToStringMethodInfo);
-        }
-        private static void TypeCastFloat2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, floatToListMethodInfo);
-        }
-        private static void TypeCastFloat2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, floatToStringMethodInfo);
-        }
-        private static void TypeCastInteger2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, integerToListMethodInfo);
-        }
-        private static void TypeCastInteger2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, intToStringMethodInfo);
-        }
-        private static void TypeCastList2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, listToStringMethodInfo);
-        }
-        private static void TypeCastObject2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, objectToStringMethodInfo);
-        }
-        private static void TypeCastRotation2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToListMethodInfo);
-        }
-        private static void TypeCastRotation2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToStringMethodInfo);
-        }
-        private static void TypeCastString2Float (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, floatConstructorStringInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
-        }
-        private static void TypeCastString2Integer (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Newobj, integerConstructorStringInfo);
-            scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
-        }
-        private static void TypeCastString2List (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, stringToListMethodInfo);
-        }
-        private static void TypeCastVector2String (IScriptCodeGen scg, Token errorAt)
-        {
-            scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToStringMethodInfo);
-        }
-
-        /*
-         * Because the calls are funky, let the compiler handle them.
-         */
-        public static bool     RotationToBool    (LSL_Rotation x) { return !x.Equals (ScriptBaseClass.ZERO_ROTATION); }
-        public static bool     StringToBool      (string x)       { return x.Length > 0; }
-        public static bool     VectorToBool      (LSL_Vector x)   { return !x.Equals (ScriptBaseClass.ZERO_VECTOR); }
-        public static string   BoolToString      (bool x)         { return x ? "1" : "0"; }
-        public static string   CharToString      (char x)         { return x.ToString (); }
-        public static string   FloatToString     (double x)  { return x.ToString ("0.000000"); }
-        public static string   IntegerToString   (int x)          { return x.ToString (); }
-        public static bool     KeyToBool         (string x)       { return (x != "") && (x != ScriptBaseClass.NULL_KEY); }
-        public static bool     ListToBool        (LSL_List x)     { return x.Length != 0; }
-        public static string   ListToString      (LSL_List x)     { return x.ToString (); }
-        public static string   ObjectToString    (object x)       { return (x == null) ? null : x.ToString (); }
-        public static string   RotationToString  (LSL_Rotation x) { return x.ToString (); }
-        public static string   VectorToString    (LSL_Vector x)   { return x.ToString (); }
-        public static LSL_List BoolToList        (bool b)         { return new LSL_List (new object[] { new LSL_Integer (b ? 1 : 0) }); }
-        public static LSL_List CharToList        (char c)         { return new LSL_List (new object[] { new LSL_Integer (c) }); }
-        public static LSL_List ExcToList         (Exception e)    { return new LSL_List (new object[] { e }); }
-        public static LSL_List VectorToList      (LSL_Vector v)   { return new LSL_List (new object[] { v }); }
-        public static LSL_List FloatToList       (double f)  { return new LSL_List (new object[] { new LSL_Float   (f) }); }
-        public static LSL_List IntegerToList     (int i)          { return new LSL_List (new object[] { new LSL_Integer (i) }); }
-        public static LSL_List RotationToList    (LSL_Rotation r) { return new LSL_List (new object[] { r }); }
-        public static LSL_List StringToList      (string s)       { return new LSL_List (new object[] { new LSL_String  (s) }); }
-
-        public static double ObjectToFloat (object x)
-        {
-            if (x is LSL_String)  return double.Parse (((LSL_String)x).m_string);
-            if (x is string)      return double.Parse ((string)x);
-            if (x is LSL_Float)   return (double)(LSL_Float)x;
-            if (x is LSL_Integer) return (double)(int)(LSL_Integer)x;
-            if (x is int)         return (double)(int)x;
-            return (double)x;
-        }
-
-        public static int ObjectToInteger (object x)
-        {
-            if (x is LSL_String)  return int.Parse (((LSL_String)x).m_string);
-            if (x is string)      return int.Parse ((string)x);
-            if (x is LSL_Integer) return (int)(LSL_Integer)x;
-            return (int)x;
-        }
-
-        public static LSL_List ObjectToList (object x)
-        {
-            return (LSL_List)x;
-        }
-
-        public static LSL_Rotation ObjectToRotation (object x)
-        {
-            if (x is LSL_String) return new LSL_Rotation (((LSL_String)x).m_string);
-            if (x is string)     return new LSL_Rotation ((string)x);
-            return (LSL_Rotation)x;
-        }
-
-        public static LSL_Vector ObjectToVector (object x)
-        {
-            if (x is LSL_String) return new LSL_Vector (((LSL_String)x).m_string);
-            if (x is string)     return new LSL_Vector ((string)x);
-            return (LSL_Vector)x;
-        }
-
-        public static string ExceptionToString (Exception x, XMRInstAbstract inst)
-        {
-            return XMRInstAbstract.xmrExceptionTypeName (x) + ": " + XMRInstAbstract.xmrExceptionMessage (x) +
-                "\n" + inst.xmrExceptionStackTrace (x);
-        }
-
-        /*
-         * These are used by event handler entrypoints to remove any LSL wrapping
-         * from the argument list and return the unboxed/unwrapped value.
-         */
-        public static double EHArgUnwrapFloat (object x)
-        {
-            if (x is LSL_Float) return (double)(LSL_Float)x;
-            return (double)x;
-        }
-
-        public static int EHArgUnwrapInteger (object x)
-        {
-            if (x is LSL_Integer) return (int)(LSL_Integer)x;
-            return (int)x;
-        }
- 
-        public static LSL_Rotation EHArgUnwrapRotation (object x)
-        {
-            if (x is OpenMetaverse.Quaternion) {
-                OpenMetaverse.Quaternion q = (OpenMetaverse.Quaternion)x;
-                return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
-            }
-            return (LSL_Rotation)x;
-        }
-
-        public static string EHArgUnwrapString (object x)
-        {
-            if (x is LSL_Key)    return (string)(LSL_Key)x;
-            if (x is LSL_String) return (string)(LSL_String)x;
-            return (string)x;
-        }
- 
-        public static LSL_Vector EHArgUnwrapVector (object x)
-        {
-            if (x is OpenMetaverse.Vector3) {
-                OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)x;
-                return new LSL_Vector(v.X, v.Y, v.Z);
-            }
-            return (LSL_Vector)x;
-        }
-    }
-}

+ 0 - 269
OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs

@@ -1,269 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @brief Perform web request
- */
-
-using System;
-using System.IO;
-using System.Net;
-using System.Text;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine {
-    public class MMRWebRequest {
-        public static bool allowFileURL = false;
-
-        public static Stream MakeRequest (string verb, string requestUrl, string obj, int timeoutms)
-        {
-            /*
-             * Pick apart the given URL and make sure we support it.
-             * For file:// URLs, just return a read-only stream of the file.
-             */
-            Uri uri = new Uri (requestUrl);
-            string supported = "http and https";
-            if (allowFileURL && (verb == "GET")) {
-                supported = "file, http and https";
-                if (uri.Scheme == "file") {
-                    return File.OpenRead (requestUrl.Substring (7));
-                }
-            }
-            bool https = uri.Scheme == "https";
-            if (!https && (uri.Scheme != "http")) {
-                throw new WebException ("only support " + supported + ", not " + uri.Scheme + " in " + requestUrl);
-            }
-            string host = uri.Host;
-            int port = uri.Port;
-            if (port < 0) port = https ? 443 : 80;
-            string path = uri.AbsolutePath;
-
-            /*
-             * Connect to the web server.
-             */
-            System.Net.Sockets.TcpClient tcpconnection = new System.Net.Sockets.TcpClient (host, port);
-            if (timeoutms > 0) {
-                tcpconnection.SendTimeout = timeoutms;
-                tcpconnection.ReceiveTimeout = timeoutms;
-            }
-
-            try {
-
-                /*
-                 * Get TCP stream to/from web server.
-                 * If HTTPS, wrap stream with SSL encryption.
-                 */
-                Stream tcpstream = tcpconnection.GetStream ();
-                if (https) {
-                    System.Net.Security.SslStream sslstream = new System.Net.Security.SslStream (tcpstream, false);
-                    sslstream.AuthenticateAsClient (host);
-                    tcpstream = sslstream;
-                }
-
-                /*
-                 * Write request header to the web server.
-                 * There might be some POST data as well to write to web server.
-                 */
-                WriteStream (tcpstream, verb + " " + path + " HTTP/1.1\r\n");
-                WriteStream (tcpstream, "Host: " + host + "\r\n");
-                if (obj != null) {
-                    byte[] bytes = Encoding.UTF8.GetBytes (obj);
-
-                    WriteStream (tcpstream, "Content-Length: " + bytes.Length + "\r\n");
-                    WriteStream (tcpstream, "Content-Type: application/x-www-form-urlencoded\r\n");
-                    WriteStream (tcpstream, "\r\n");
-                    tcpstream.Write (bytes, 0, bytes.Length);
-                } else {
-                    WriteStream (tcpstream, "\r\n");
-                }
-                tcpstream.Flush ();
-
-                /*
-                 * Check for successful reply status line.
-                 */
-                string headerline = ReadStreamLine (tcpstream).Trim ();
-                if (headerline != "HTTP/1.1 200 OK") throw new WebException ("status line " + headerline);
-
-                /*
-                 * Scan through header lines.
-                 * The only ones we care about are Content-Length and Transfer-Encoding.
-                 */
-                bool chunked = false;
-                int contentlength = -1;
-                while ((headerline = ReadStreamLine (tcpstream).Trim ().ToLowerInvariant ()) != "") {
-                    if (headerline.StartsWith ("content-length:")) {
-                        contentlength = int.Parse (headerline.Substring (15));
-                    }
-                    if (headerline.StartsWith ("transfer-encoding:") && (headerline.Substring (18).Trim () == "chunked")) {
-                        chunked = true;
-                    }
-                }
-
-                /*
-                 * Read response byte array as a series of chunks.
-                 */
-                if (chunked) {
-                    return new ChunkedStreamReader (tcpstream);
-                }
-
-                /*
-                 * Read response byte array with the exact length given by Content-Length.
-                 */
-                if (contentlength >= 0) {
-                    return new LengthStreamReader (tcpstream, contentlength);
-                }
-
-                /*
-                 * Don't know how it is being transferred.
-                 */
-                throw new WebException ("header missing content-length or transfer-encoding: chunked");
-            } catch {
-                tcpconnection.Close ();
-                throw;
-            }
-        }
-
-        /**
-         * @brief Write the string out as ASCII bytes.
-         */
-        private static void WriteStream (Stream stream, string line)
-        {
-            byte[] bytes = Encoding.ASCII.GetBytes (line);
-            stream.Write (bytes, 0, bytes.Length);
-        }
-
-        /**
-         * @brief Read the next text line from a stream.
-         * @returns string with \r\n trimmed off
-         */
-        private static string ReadStreamLine (Stream stream)
-        {
-            StringBuilder sb = new StringBuilder ();
-            while (true) {
-                int b = stream.ReadByte ();
-                if (b < 0) break;
-                if (b == '\n') break;
-                if (b == '\r') continue;
-                sb.Append ((char)b);
-            }
-            return sb.ToString ();
-        }
-
-        private class ChunkedStreamReader : Stream {
-            private int chunklen;
-            private Stream tcpstream;
-
-            public ChunkedStreamReader (Stream tcpstream)
-            {
-                this.tcpstream = tcpstream;
-            }
-
-            public override bool CanRead    { get { return true;  } }
-            public override bool CanSeek    { get { return false; } }
-            public override bool CanTimeout { get { return false; } }
-            public override bool CanWrite   { get { return false; } }
-            public override long Length     { get { return 0; } }
-            public override long Position   { get { return 0; } set { } }
-            public override void Flush ()   { }
-            public override long Seek (long offset, SeekOrigin origin) { return 0; }
-            public override void SetLength (long length) { }
-            public override void Write (byte[] buffer, int offset, int length) { }
-
-            public override int Read (byte[] buffer, int offset, int length)
-            {
-                if (length <= 0) return 0;
-
-                if (chunklen == 0) {
-                    chunklen = int.Parse (ReadStreamLine (tcpstream), System.Globalization.NumberStyles.HexNumber);
-                    if (chunklen < 0) throw new WebException ("negative chunk length");
-                    if (chunklen == 0) chunklen = -1;
-                }
-                if (chunklen < 0) return 0;
-
-                int maxread = (length < chunklen) ? length : chunklen;
-                int lenread = tcpstream.Read (buffer, offset, maxread);
-                chunklen -= lenread;
-                if (chunklen == 0) {
-                    int b = tcpstream.ReadByte ();
-                    if (b == '\r') b = tcpstream.ReadByte ();
-                    if (b != '\n') throw new WebException ("chunk not followed by \\r\\n");
-                }
-                return lenread;
-            }
-
-            public override void Close ()
-            {
-                chunklen = -1;
-                if (tcpstream != null) {
-                    tcpstream.Close ();
-                    tcpstream = null;
-                }
-            }
-        }
-
-        private class LengthStreamReader : Stream {
-            private int contentlength;
-            private Stream tcpstream;
-
-            public LengthStreamReader (Stream tcpstream, int contentlength)
-            {
-                this.tcpstream = tcpstream;
-                this.contentlength = contentlength;
-            }
-
-            public override bool CanRead    { get { return true;  } }
-            public override bool CanSeek    { get { return false; } }
-            public override bool CanTimeout { get { return false; } }
-            public override bool CanWrite   { get { return false; } }
-            public override long Length     { get { return 0; } }
-            public override long Position   { get { return 0; } set { } }
-            public override void Flush ()   { }
-            public override long Seek (long offset, SeekOrigin origin) { return 0; }
-            public override void SetLength (long length) { }
-            public override void Write (byte[] buffer, int offset, int length) { }
-
-            public override int Read (byte[] buffer, int offset, int length)
-            {
-                if (length <= 0) return 0;
-                if (contentlength <= 0) return 0;
-
-                int maxread = (length < contentlength) ? length : contentlength;
-                int lenread = tcpstream.Read (buffer, offset, maxread);
-                contentlength -= lenread;
-                return lenread;
-            }
-
-            public override void Close ()
-            {
-                contentlength = -1;
-                if (tcpstream != null) {
-                    tcpstream.Close ();
-                    tcpstream = null;
-                }
-            }
-        }
-    }
-}

+ 0 - 491
OpenSim/Region/ScriptEngine/XMREngine/XMREngXmrTestLs.cs

@@ -1,491 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using log4net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public partial class XMREngine {
-
-        private void XmrTestLs (string[] args, int indx)
-        {
-            bool flagFull   = false;
-            bool flagQueues = false;
-            bool flagTopCPU = false;
-            int maxScripts  = 0x7FFFFFFF;
-            int numScripts  = 0;
-            string outName  = null;
-            XMRInstance[] instances;
-
-            /*
-             * Decode command line options.
-             */
-            for (int i = indx; i < args.Length; i ++) {
-                if (args[i] == "-full") {
-                    flagFull = true;
-                    continue;
-                }
-                if (args[i] == "-help") {
-                    m_log.Info ("[XMREngine]: xmr ls -full -max=<number> -out=<filename> -queues -topcpu");
-                    return;
-                }
-                if (args[i].StartsWith("-max=")) {
-                    try {
-                        maxScripts = Convert.ToInt32(args[i].Substring(5));
-                    } catch (Exception e) {
-                        m_log.Error("[XMREngine]: bad max " + args[i].Substring(5) + ": " + e.Message);
-                        return;
-                    }
-                    continue;
-                }
-                if (args[i].StartsWith("-out=")) {
-                    outName = args[i].Substring(5);
-                    continue;
-                }
-                if (args[i] == "-queues") {
-                    flagQueues = true;
-                    continue;
-                }
-                if (args[i] == "-topcpu") {
-                    flagTopCPU = true;
-                    continue;
-                }
-                if (args[i][0] == '-') {
-                    m_log.Error("[XMREngine]: unknown option " + args[i] + ", try 'xmr ls -help'");
-                    return;
-                }
-            }
-
-            TextWriter outFile = null;
-            if (outName != null) {
-                try {
-                    outFile = File.CreateText(outName);
-                } catch (Exception e) {
-                    m_log.Error("[XMREngine]: error creating " + outName + ": " + e.Message);
-                    return;
-                }
-            } else {
-                outFile = new LogInfoTextWriter(m_log);
-            }
-
-            try {
-                for (int i = 0; i < numThreadScriptWorkers; i ++) {
-                    XMRScriptThread th = m_ScriptThreads[i];
-                    outFile.WriteLine("Script thread ID: " + th.m_ScriptThreadTID);
-                    long execTime = th.m_ScriptExecTime;
-                    if (execTime < 0) {
-                        execTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
-                    }
-                    outFile.WriteLine("  execution time: " + execTime + " mS");
-                    outFile.WriteLine("     last ran at: " + th.m_LastRanAt.ToString());
-                    XMRInstance rins = th.m_RunInstance;
-                    if (rins != null) {
-                        outFile.WriteLine("         running: " + rins.ItemID.ToString() + " " + rins.m_DescName);
-                        if (flagFull) {
-                            outFile.WriteLine (rins.RunTestLs (true));
-                        }
-                    }
-                }
-
-                /*
-                 * Scan instance list to find those that match selection criteria.
-                 */
-                if (!Monitor.TryEnter(m_InstancesDict, 100)) {
-                    m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
-                    return;
-                }
-                try
-                {
-                    instances = new XMRInstance[m_InstancesDict.Count];
-                    foreach (XMRInstance ins in m_InstancesDict.Values)
-                    {
-                        if (InstanceMatchesArgs(ins, args, indx)) {
-                            instances[numScripts++] = ins;
-                        }
-                    }
-                } finally {
-                    Monitor.Exit(m_InstancesDict);
-                }
-    
-                /*
-                 * Maybe sort by descending CPU time.
-                 */
-                if (flagTopCPU) {
-                    Array.Sort<XMRInstance>(instances, CompareInstancesByCPUTime);
-                }
-    
-                /*
-                 * Print the entries.
-                 */
-                if (!flagFull) {
-                    outFile.WriteLine("                              ItemID" + 
-                                      "   CPU(ms)" +
-                                      " NumEvents" +
-                                      " Status    " +
-                                      " World Position                  " +
-                                      " <Part>:<Item>");
-                }
-                for (int i = 0; (i < numScripts) && (i < maxScripts); i ++) {
-                    outFile.WriteLine(instances[i].RunTestLs(flagFull));
-                }
-
-                /*
-                 * Print number of scripts that match selection criteria,
-                 * even if we were told to print fewer.
-                 */
-                outFile.WriteLine("total of {0} script(s)", numScripts);
-
-                /*
-                 * If -queues given, print out queue contents too.
-                 */
-                if (flagQueues) {
-                    LsQueue(outFile, "start", m_StartQueue, args, indx);
-                    LsQueue(outFile, "sleep", m_SleepQueue, args, indx);
-                    LsQueue(outFile, "yield", m_YieldQueue, args, indx);
-                }
-            } finally {
-                outFile.Close();
-            }
-        }
-
-        private void XmrTestPev (string[] args, int indx)
-        {
-            bool flagAll = false;
-            int numScripts = 0;
-            XMRInstance[] instances;
-
-            /*
-             * Decode command line options.
-             */
-            int i, j;
-            List<string> selargs = new List<string> (args.Length);
-            MethodInfo[] eventmethods = typeof (IEventHandlers).GetMethods ();
-            MethodInfo eventmethod;
-            for (i = indx; i < args.Length; i ++) {
-                string arg = args[i];
-                if (arg == "-all") {
-                    flagAll = true;
-                    continue;
-                }
-                if (arg == "-help") {
-                    m_log.Info ("[XMREngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
-                    return;
-                }
-                if (arg[0] == '-') {
-                    m_log.Error ("[XMREngine]: unknown option " + arg + ", try 'xmr pev -help'");
-                    return;
-                }
-                for (j = 0; j < eventmethods.Length; j ++) {
-                    eventmethod = eventmethods[j];
-                    if (eventmethod.Name == arg) goto gotevent;
-                }
-                selargs.Add (arg);
-            }
-            m_log.Error ("[XMREngine]: missing <event-name> <params...>, try 'xmr pev -help'");
-            return;
-        gotevent:
-            string eventname = eventmethod.Name;
-            StringBuilder sourcesb = new StringBuilder ();
-            while (++ i < args.Length) {
-                sourcesb.Append (' ');
-                sourcesb.Append (args[i]);
-            }
-            string sourcest = sourcesb.ToString ();
-            string sourcehash;
-            youveanerror = false;
-            Token t = TokenBegin.Construct ("", null, ErrorMsg, sourcest, out sourcehash);
-            if (youveanerror) return;
-            ParameterInfo[] paraminfos = eventmethod.GetParameters ();
-            object[] paramvalues = new object[paraminfos.Length];
-            i = 0;
-            while (!((t = t.nextToken) is TokenEnd)) {
-                if (i >= paramvalues.Length) {
-                    ErrorMsg (t, "extra parameter(s)");
-                    return;
-                }
-                paramvalues[i] = ParseParamValue (ref t);
-                if (paramvalues[i] == null) return;
-                i ++;
-            }
-            OpenSim.Region.ScriptEngine.Shared.EventParams eps = 
-                    new OpenSim.Region.ScriptEngine.Shared.EventParams (eventname, paramvalues, zeroDetectParams);
-
-            /*
-             * Scan instance list to find those that match selection criteria.
-             */
-            if (!Monitor.TryEnter(m_InstancesDict, 100)) {
-                m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
-                return;
-            }
-
-            try {
-                instances = new XMRInstance[m_InstancesDict.Count];
-                foreach (XMRInstance ins in m_InstancesDict.Values) {
-                    if (flagAll || InstanceMatchesArgs (ins, selargs.ToArray (), 0)) {
-                        instances[numScripts++] = ins;
-                    }
-                }
-            } finally {
-                Monitor.Exit(m_InstancesDict);
-            }
-    
-            /*
-             * Post event to the matching instances.
-             */
-            for (i = 0; i < numScripts; i ++) {
-                XMRInstance inst = instances[i];
-                m_log.Info ("[XMREngine]: post " + eventname + " to " + inst.m_DescName);
-                inst.PostEvent (eps);
-            }
-        }
-
-        private object ParseParamValue (ref Token token)
-        {
-            if (token is TokenFloat) {
-                return new LSL_Float (((TokenFloat)token).val);
-            }
-            if (token is TokenInt) {
-                return new LSL_Integer (((TokenInt)token).val);
-            }
-            if (token is TokenStr) {
-                return new LSL_String (((TokenStr)token).val);
-            }
-            if (token is TokenKwCmpLT) {
-                List<double> valuelist = new List<double> ();
-                while (!((token = token.nextToken) is TokenKwCmpGT)) {
-                    if (!(token is TokenKwComma)) {
-                        object value = ParseParamValue (ref token);
-                        if (value == null) return null;
-                        if (value is int) value = (double)(int)value;
-                        if (!(value is double)) {
-                            ErrorMsg (token, "must be float or integer constant");
-                            return null;
-                        }
-                        valuelist.Add ((double)value);
-                    } else if (token.prevToken is TokenKwComma) {
-                        ErrorMsg (token, "missing constant");
-                        return null;
-                    }
-                }
-                double[] values = valuelist.ToArray ();
-                switch (values.Length) {
-                    case 3: {
-                        return new LSL_Vector (values[0], values[1], values[2]);
-                    }
-                    case 4: {
-                        return new LSL_Rotation (values[0], values[1], values[2], values[3]);
-                    }
-                    default: {
-                        ErrorMsg (token, "not rotation or vector");
-                        return null;
-                    }
-                }
-            }
-            if (token is TokenKwBrkOpen) {
-                List<object> valuelist = new List<object> ();
-                while (!((token = token.nextToken) is TokenKwBrkClose)) {
-                    if (!(token is TokenKwComma)) {
-                        object value = ParseParamValue (ref token);
-                        if (value == null) return null;
-                        valuelist.Add (value);
-                    } else if (token.prevToken is TokenKwComma) {
-                        ErrorMsg (token, "missing constant");
-                        return null;
-                    }
-                }
-                return new LSL_List (valuelist.ToArray ());
-            }
-            if (token is TokenName) {
-                FieldInfo field = typeof (OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass).GetField (((TokenName)token).val);
-                if ((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly))) {
-                    return field.GetValue (null);
-                }
-            }
-            ErrorMsg (token, "invalid constant");
-            return null;
-        }
-
-        private bool youveanerror;
-        private void ErrorMsg (Token token, string message)
-        {
-            youveanerror = true;
-            m_log.Info ("[XMREngine]: " + token.posn + " " + message);
-        }
-
-        private void XmrTestReset (string[] args, int indx)
-        {
-            bool flagAll = false;
-            int numScripts = 0;
-            XMRInstance[] instances;
-
-            if (args.Length <= indx) {
-                m_log.Error("[XMREngine]: must specify part of script name or -all for all scripts");
-                return;
-            }
-
-            /*
-             * Decode command line options.
-             */
-            for (int i = indx; i < args.Length; i ++) {
-                if (args[i] == "-all") {
-                    flagAll = true;
-                    continue;
-                }
-                if (args[i] == "-help") {
-                    m_log.Info ("[XMREngine]: xmr reset -all | <part-of-script-name>");
-                    return;
-                }
-                if (args[i][0] == '-') {
-                    m_log.Error ("[XMREngine]: unknown option " + args[i] + ", try 'xmr reset -help'");
-                    return;
-                }
-            }
-
-            /*
-             * Scan instance list to find those that match selection criteria.
-             */
-            if (!Monitor.TryEnter(m_InstancesDict, 100)) {
-                m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
-                return;
-            }
-
-            try {
-                instances = new XMRInstance[m_InstancesDict.Count];
-                foreach (XMRInstance ins in m_InstancesDict.Values) {
-                    if (flagAll || InstanceMatchesArgs (ins, args, indx)) {
-                        instances[numScripts++] = ins;
-                    }
-                }
-            } finally {
-                Monitor.Exit(m_InstancesDict);
-            }
-    
-            /*
-             * Reset the instances as if someone clicked their "Reset" button.
-             */
-            for (int i = 0; i < numScripts; i ++) {
-                XMRInstance inst = instances[i];
-                m_log.Info ("[XMREngine]: resetting " + inst.m_DescName);
-                inst.Reset();
-            }
-        }
-
-        private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b)
-        {
-            if (a == null) {
-                return (b == null) ? 0 : 1;
-            }
-            if (b == null) {
-                return -1;
-            }
-            if (b.m_CPUTime < a.m_CPUTime) return -1;
-            if (b.m_CPUTime > a.m_CPUTime) return  1;
-            return 0;
-        }
-
-        private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx)
-        {
-            outFile.WriteLine("Queue " + name + ":");
-            lock (queue) {
-                for (XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst) {
-                    try {
-
-                        /*
-                         * Try to print instance name.
-                         */
-                        if (InstanceMatchesArgs(inst, args, indx)) {
-                            outFile.WriteLine("   " + inst.ItemID.ToString() + " " + inst.m_DescName);
-                        }
-                    } catch (Exception e) {
-
-                        /*
-                         * Sometimes there are instances in the queue that are disposed.
-                         */
-                        outFile.WriteLine("   " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message);
-                    }
-                }
-            }
-        }
-
-        private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx)
-        {
-            bool hadSomethingToCompare = false;
-
-            for (int i = indx; i < args.Length; i ++)
-            {
-                if (args[i][0] != '-') {
-                    hadSomethingToCompare = true;
-                    if (ins.m_DescName.Contains(args[i])) return true;
-                    if (ins.ItemID.ToString().Contains(args[i])) return true;
-                    if (ins.AssetID.ToString().Contains(args[i])) return true;
-                }
-            }
-            return !hadSomethingToCompare;
-        }
-    }
-
-    /**
-     * @brief Make m_log.Info look like a text writer.
-     */
-    public class LogInfoTextWriter : TextWriter {
-        private StringBuilder sb = new StringBuilder();
-        private ILog m_log;
-        public LogInfoTextWriter (ILog m_log)
-        {
-            this.m_log = m_log;
-        }
-        public override void Write (char c)
-        {
-            if (c == '\n') {
-                m_log.Info("[XMREngine]: " + sb.ToString());
-                sb.Remove(0, sb.Length);
-            } else {
-                sb.Append(c);
-            }
-        }
-        public override void Close () { }
-        public override Encoding Encoding {
-            get {
-                return Encoding.UTF8;
-            }
-        }
-    }
-}

+ 0 - 2102
OpenSim/Region/ScriptEngine/XMREngine/XMREngine.cs

@@ -1,2102 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// based on XMREngine from Mike Rieker (Dreamnation) and Melanie Thielker
-// but with several changes to be more cross platform.
-
-
-using log4net;
-using Mono.Addins;
-using Nini.Config;
-using OpenSim.Framework;
-using OpenSim.Framework.Console;
-using OpenSim.Framework.Monitoring;
-using OpenSim.Region.ClientStack.Linden;
-using OpenSim.Region.Framework.Interfaces;
-using OpenSim.Region.Framework.Scenes;
-using OpenSim.Region.ScriptEngine.Interfaces;
-using OpenSim.Region.ScriptEngine.Shared;
-using OpenSim.Region.ScriptEngine.Shared.Api;
-using OpenMetaverse;
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-using System.Threading;
-using System.Timers;
-using System.Xml;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-[assembly: Addin("XMREngine", OpenSim.VersionInfo.VersionNumber)]
-[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XMREngine")]
-    public partial class XMREngine : INonSharedRegionModule, IScriptEngine,
-            IScriptModule
-    {
-        public  static readonly DetectParams[] zeroDetectParams = new DetectParams[0];
-        private static ArrayList noScriptErrors = new ArrayList();
-        public  static readonly ILog m_log =
-            LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-        private static readonly string[] scriptReferencedAssemblies = new string[0];
-
-        private bool m_LateInit;
-        private bool m_TraceCalls;
-        public  bool m_Verbose;
-        public  bool m_ScriptDebug;
-        public  Scene m_Scene;
-        private IConfigSource m_ConfigSource;
-        private IConfig m_Config;
-        private string m_ScriptBasePath;
-        private bool m_Enabled = false;
-        public  bool m_StartProcessing = false;
-        public  bool m_UseSourceHashCode = false;
-        public  ConstructorInfo uThreadCtor;
-        private Dictionary<UUID, ArrayList> m_ScriptErrors =
-                new Dictionary<UUID, ArrayList>();
-        private Dictionary<UUID, List<UUID>> m_ObjectItemList =
-                new Dictionary<UUID, List<UUID>>();
-        private Dictionary<UUID, XMRInstance[]> m_ObjectInstArray =
-                new Dictionary<UUID, XMRInstance[]>();
-        public  Dictionary<string,FieldInfo> m_XMRInstanceApiCtxFieldInfos =
-                new Dictionary<string,FieldInfo> ();
-        private int m_StackSize;
-        private int m_HeapSize;
-
-        private XMRScriptThread[] m_ScriptThreads;
-        private int    m_WakeUpOne  = 0;
-        public  object m_WakeUpLock = new object();
-        private Dictionary<Thread,XMRScriptThread> m_AllThreads = new Dictionary<Thread,XMRScriptThread> ();
-
-        private bool m_SuspendScriptThreadFlag = false;
-        /**
-         * @brief Something was just added to the Start or Yield queue so
-         *        wake one of the XMRScriptThread instances to run it.
-         */
-
-        private Thread m_SleepThread = null;
-        private bool m_Exiting = false;
-
-        private int m_MaintenanceInterval = 10;
-        private System.Timers.Timer m_MaintenanceTimer;
-        public  int numThreadScriptWorkers;
-
-        private object m_FrameUpdateLock = new object ();
-        private event ThreadStart m_FrameUpdateList = null;
-
-         // Various instance lists:
-         //   m_InstancesDict = all known instances
-         //                     find an instance given its itemID
-         //   m_StartQueue = instances that have just had event queued to them
-         //   m_YieldQueue = instances that are ready to run right now
-         //   m_SleepQueue = instances that have m_SleepUntil valid
-         //                  sorted by ascending m_SleepUntil
-
-        private Dictionary<UUID, XMRInstance> m_InstancesDict =
-                new Dictionary<UUID, XMRInstance>();
-        public  Queue<ThreadStart> m_ThunkQueue = new Queue<ThreadStart> ();
-        public  XMRInstQueue m_StartQueue = new XMRInstQueue();
-        public  XMRInstQueue m_YieldQueue = new XMRInstQueue();
-        public  XMRInstQueue m_SleepQueue = new XMRInstQueue();
-        private string m_LockedDict = "nobody";
-
-        public XMREngine()
-        {
-        }
-
-        public string Name
-        {
-            get { return "XMREngine"; }
-        }
-
-        public Type ReplaceableInterface
-        {
-            get { return null; }
-        }
-
-        public string ScriptEnginePath
-        {
-            get { return m_ScriptBasePath; }
-        }
-
-        public string ScriptClassName
-        {
-            get { return "XMREngineScript"; }
-        }
-
-        public string ScriptBaseClassName
-        {
-            get { return typeof (XMRInstance).FullName; }
-        }
-
-        public ParameterInfo[] ScriptBaseClassParameters
-        {
-            get { return typeof(XMRInstance).GetConstructor (new Type[] { typeof (WaitHandle) }).GetParameters (); }
-        }
-
-        public string[] ScriptReferencedAssemblies
-        {
-            get { return scriptReferencedAssemblies; }
-        }
-
-        public void WakeUpOne()
-        {
-            lock (m_WakeUpLock)
-            {
-                m_WakeUpOne++;
-                Monitor.Pulse(m_WakeUpLock);
-            }
-        }
-
-        public void AddThread(Thread thd, XMRScriptThread xthd)
-        {
-            lock(m_AllThreads)
-                m_AllThreads.Add(thd, xthd);
-        }
-
-        public void RemoveThread(Thread thd)
-        {
-            lock(m_AllThreads)
-                m_AllThreads.Remove(thd);
-        }
-
-        public XMRScriptThread CurrentScriptThread ()
-        {
-            XMRScriptThread st;
-            lock (m_AllThreads)
-                m_AllThreads.TryGetValue (Thread.CurrentThread, out st);
-
-            return st;
-        }
-
-        public void Initialise(IConfigSource config)
-        {
-            TraceCalls("[XMREngine]: Initialize entry");
-            m_ConfigSource = config;
-
-            ////foreach (IConfig icfg in config.Configs) {
-            ////    m_log.Debug("[XMREngine]: Initialise: configs[" + icfg.Name + "]");
-            ////    foreach (string key in icfg.GetKeys ()) {
-            ////        m_log.Debug("[XMREngine]: Initialise:     " + key + "=" + icfg.GetExpanded (key));
-            ////    }
-            ////}
-
-            m_Enabled = false;
-            m_Config = config.Configs["XMREngine"];
-            if (m_Config == null)
-            {
-                m_log.Info("[XMREngine]: no config, assuming disabled");
-                return;
-            }
-
-            m_Enabled = m_Config.GetBoolean("Enabled", false);
-            m_log.InfoFormat("[XMREngine]: config enabled={0}", m_Enabled);
-            if (!m_Enabled)
-                return;
-
-            Type uThreadType = null;
-            uThreadType = typeof (ScriptUThread_Nul);
-            uThreadCtor = uThreadType.GetConstructor (new Type[] { typeof (XMRInstance) });
-
-            m_UseSourceHashCode    = m_Config.GetBoolean("UseSourceHashCode", false);
-            numThreadScriptWorkers = m_Config.GetInt("NumThreadScriptWorkers", 3);
-            m_ScriptThreads        = new XMRScriptThread[numThreadScriptWorkers];
-
-            m_TraceCalls           = m_Config.GetBoolean("TraceCalls", false);
-            m_Verbose              =  m_Config.GetBoolean("Verbose", false);
-            m_ScriptDebug          = m_Config.GetBoolean("ScriptDebug", false);
-
-             // Verify that our ScriptEventCode's match OpenSim's scriptEvent's.
-            bool err = false;
-            for (int i = 0; i < 32; i ++)
-            {
-                string mycode = "undefined";
-                string oscode = "undefined";
-                try
-                {
-                    mycode = ((ScriptEventCode)i).ToString();
-                    Convert.ToInt32(mycode);
-                    mycode = "undefined";
-                }
-                catch { }
-                try
-                {
-                    oscode = ((OpenSim.Region.Framework.Scenes.scriptEvents)(1 << i)).ToString();
-                    Convert.ToInt32(oscode);
-                    oscode = "undefined";
-                }
-                catch { }
-                if (mycode != oscode)
-                {
-                    m_log.ErrorFormat("[XMREngine]: {0} mycode={1}, oscode={2}", i, mycode, oscode);
-                    err = true;
-                }
-            }
-            if (err)
-            {
-                m_Enabled = false;
-                return;
-            }
-
-            for (int i = 0; i < numThreadScriptWorkers; i ++)
-            {
-                m_ScriptThreads[i] = new XMRScriptThread(this, i);;
-            }
-
-
-            m_SleepThread = StartMyThread(RunSleepThread, "xmrengine sleep", ThreadPriority.Normal);
-
-            m_StackSize = m_Config.GetInt("ScriptStackSize", 2048) << 10;
-            m_HeapSize  = m_Config.GetInt("ScriptHeapSize",  1024) << 10;
-
-            m_log.InfoFormat("[XMREngine]: Enabled, {0}.{1} Meg (0x{2}) stacks",
-                    (m_StackSize >> 20).ToString (),
-                    (((m_StackSize % 0x100000) * 1000) 
-                            >> 20).ToString ("D3"),
-                    m_StackSize.ToString ("X"));
-
-            m_log.InfoFormat("[XMREngine]:  ... {0}.{1} Meg (0x{2}) heaps",
-                    (m_HeapSize >> 20).ToString (),
-                    (((m_HeapSize % 0x100000) * 1000) 
-                            >> 20).ToString ("D3"),
-                    m_HeapSize.ToString ("X"));
-
-            m_MaintenanceInterval = m_Config.GetInt("MaintenanceInterval", 10);
-
-            if (m_MaintenanceInterval > 0)
-            {
-                m_MaintenanceTimer = new System.Timers.Timer(m_MaintenanceInterval * 60000);
-                m_MaintenanceTimer.Elapsed += DoMaintenance;
-                m_MaintenanceTimer.Start();
-            }
-
-            MainConsole.Instance.Commands.AddCommand("xmr", false,
-                    "xmr",
-                    "xmr [...|help|...] ...",
-                    "Run xmr script engine commands",
-                    RunTest);
-
-            TraceCalls("[XMREngine]: Initialize successful");
-        }
-
-        public void AddRegion(Scene scene)
-        {
-            if (!m_Enabled)
-                return;
-
-            TraceCalls("[XMREngine]: XMREngine.AddRegion({0})", scene.RegionInfo.RegionName);
-
-            m_Scene = scene;
-
-            m_Scene.RegisterModuleInterface<IScriptModule>(this);
-
-            m_ScriptBasePath = m_Config.GetString ("ScriptBasePath", "ScriptData");
-            m_ScriptBasePath = Path.Combine (m_ScriptBasePath, scene.RegionInfo.RegionID.ToString());
-
-            Directory.CreateDirectory(m_ScriptBasePath);
-
-            m_Scene.EventManager.OnRezScript += OnRezScript;
-
-            m_Scene.StackModuleInterface<IScriptModule>(this);
-        }
-
-        private void OneTimeLateInitialization ()
-        {
-             // Build list of defined APIs and their 'this' types and define a field in XMRInstanceSuperType.
-            ApiManager am = new ApiManager ();
-            Dictionary<string,Type> apiCtxTypes = new Dictionary<string,Type> ();
-            foreach (string api in am.GetApis ())
-            {
-                m_log.Debug ("[XMREngine]: adding api " + api);
-                IScriptApi scriptApi = am.CreateApi (api);
-                Type apiCtxType = scriptApi.GetType ();
-                if (api == "LSL") apiCtxType = typeof (XMRLSL_Api);
-                apiCtxTypes[api] = apiCtxType;
-            }
-
-            if (ScriptCodeGen.xmrInstSuperType == null) // Only create type once!
-            {
-                 // Start creating type XMRInstanceSuperType that contains a field
-                 // m_ApiManager_<APINAME> that points to the per-instance context
-                 // struct for that API, ie, the 'this' value passed to all methods
-                 // in that API.  It is in essence:
-
-                 //  public class XMRInstanceSuperType : XMRInstance {
-                 //      public XMRLSL_Api m_ApiManager_LSL;   // 'this' value for all ll...() functions
-                 //      public MOD_Api    m_ApiManager_MOD;   // 'this' value for all mod...() functions
-                 //      public OSSL_Api   m_ApiManager_OSSL;  // 'this' value for all os...() functions
-                 //              ....
-                 //  }
-
-                AssemblyName assemblyName = new AssemblyName ();
-                assemblyName.Name = "XMRInstanceSuperAssembly";
-                AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
-#if DEBUG
-                Type daType = typeof(DebuggableAttribute);
-                ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
-
-                CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] {
-                    DebuggableAttribute.DebuggingModes.DisableOptimizations |
-                    DebuggableAttribute.DebuggingModes.EnableEditAndContinue |
-                    DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
-                    DebuggableAttribute.DebuggingModes.Default });
-
-                assemblyBuilder.SetCustomAttribute(daBuilder);
-#endif
-                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("XMRInstanceSuperModule");
-                TypeBuilder typeBuilder = moduleBuilder.DefineType("XMRInstanceSuperType", TypeAttributes.Public | TypeAttributes.Class);
-                typeBuilder.SetParent(typeof (XMRInstance));
-
-                foreach (string apiname in apiCtxTypes.Keys)
-                {
-                    string fieldName = "m_ApiManager_" + apiname;
-                    typeBuilder.DefineField (fieldName, apiCtxTypes[apiname], FieldAttributes.Public);
-                }
-
-                 // Finalize definition of XMRInstanceSuperType.
-                 // Give the compiler a short name to reference it by,
-                 // otherwise it will try to use the AssemblyQualifiedName
-                 // and fail miserably.
-                ScriptCodeGen.xmrInstSuperType = typeBuilder.CreateType ();
-                ScriptObjWriter.DefineInternalType ("xmrsuper", ScriptCodeGen.xmrInstSuperType);
-            }
-
-             // Tell the compiler about all the constants and methods for each API.
-             // We also tell the compiler how to get the per-instance context for each API
-             // by reading the corresponding m_ApiManager_<APINAME> field of XMRInstanceSuperType.
-
-            foreach (KeyValuePair<string,Type> kvp in apiCtxTypes)
-            {
-                // get API name and the corresponding per-instance context type
-                string api = kvp.Key;
-                Type apiCtxType = kvp.Value;
-
-                // give script compiler an abbreviated name for the API context type
-                ScriptObjWriter.DefineInternalType ("apimanager_" + api, apiCtxType);
-
-                // this field tells the compiled code where the per-instance API context object is
-                // eg, for the OSSL API, it is in ((XMRInstanceSuperType)inst).m_ApiManager_OSSL
-                string fieldName = "m_ApiManager_" + api;
-                FieldInfo fieldInfo = ScriptCodeGen.xmrInstSuperType.GetField (fieldName);
-                m_XMRInstanceApiCtxFieldInfos[api] = fieldInfo;
-
-                // now tell the compiler about the constants and methods for the API
-                ScriptConst.AddInterfaceConstants   (null, apiCtxType.GetFields ());
-                TokenDeclInline.AddInterfaceMethods (null, apiCtxType.GetMethods (), fieldInfo);
-            }
-
-             // Add sim-specific APIs to the compiler.
-
-            IScriptModuleComms comms = m_Scene.RequestModuleInterface<IScriptModuleComms> ();
-            if (comms != null)
-            {
-                 // Add methods to list of built-in functions.
-                Delegate[] methods = comms.GetScriptInvocationList ();
-                foreach (Delegate m in methods)
-                {
-                    MethodInfo mi = m.Method;
-                    try
-                    {
-                        CommsCallCodeGen cccg = new CommsCallCodeGen (mi, comms, m_XMRInstanceApiCtxFieldInfos["MOD"]);
-                        Verbose ("[XMREngine]: added comms function " + cccg.fullName);
-                    }
-                    catch (Exception e)
-                    {
-                        m_log.Error ("[XMREngine]: failed to add comms function " + mi.Name);
-                        m_log.Error ("[XMREngine]: - " + e.ToString ());
-                    }
-                }
-
-                 // Add constants to list of built-in constants.
-
-                Dictionary<string,object> consts = comms.GetConstants ();
-                foreach (KeyValuePair<string,object> kvp in consts)
-                {
-                    try
-                    {
-                        ScriptConst sc = ScriptConst.AddConstant (kvp.Key, kvp.Value);
-                        Verbose ("[XMREngine]: added comms constant " + sc.name);
-                    }
-                    catch (Exception e)
-                    {
-                        m_log.Error ("[XMREngine]: failed to add comms constant " + kvp.Key);
-                        m_log.Error ("[XMREngine]: - " + e.Message);
-                    }
-                }
-            }
-            else
-            {
-                Verbose ("[XMREngine]: comms not enabled");
-            }
-        }
-
-        /**
-         * @brief Generate code for the calls to the comms functions.
-         *        It is a tRUlY EvIL interface.
-         *        To call the function we must call an XMRInstanceSuperType.m_ApiManager_MOD.modInvoker?()
-         *        method passing it the name of the function as a string and the script
-         *        argument list wrapped up in an object[] array.  The modInvoker?() methods 
-         *        do some sick type conversions (with corresponding mallocs) so we can't 
-         *        call the methods directly.
-         */
-        private class CommsCallCodeGen : TokenDeclInline
-        {
-            private static Type[] modInvokerArgTypes = new Type[] { typeof (string), typeof (object[]) };
-            public  static FieldInfo xmrInstModApiCtxField;
-
-            private MethodInfo modInvokerMeth;
-            private string methName;
-
-            /**
-             * @brief Constructor
-             * @param mi = method to make available to scripts
-             *        mi.Name = name that is used by scripts
-             *        mi.GetParameters() = parameter list as defined by module
-             *                             includes the 'UUID host','UUID script' parameters that script does not see
-             *                             allowed types for script-visible parameters are as follows:
-             *                                    Single -> float
-             *                                     Int32 -> integer
-             *                        OpenMetaverse.UUID -> key
-             *                                  Object[] -> list
-             *                  OpenMetaverse.Quaternion -> rotation
-             *                                    String -> string
-             *                     OpenMetaverse.Vector3 -> vector
-             *        mi.ReturnType = return type as defined by module
-             *                        types are same as allowed for parameters
-             * @param comms = comms module the method came from
-             * @param apictxfi = what field in XMRInstanceSuperType the 'this' value is for this method
-             */
-            public CommsCallCodeGen (MethodInfo mi, IScriptModuleComms comms, FieldInfo apictxfi)
-                    : base (null, false, NameArgSig (mi), RetType (mi))
-            {
-                methName = mi.Name;
-                string modInvokerName = comms.LookupModInvocation (methName);
-                if (modInvokerName == null)
-                    throw new Exception("cannot find comms method " + methName);
-                modInvokerMeth = typeof(MOD_Api).GetMethod(modInvokerName, modInvokerArgTypes);
-                xmrInstModApiCtxField = apictxfi;
-            }
-
-            // script-visible name(argtype,...) signature string
-            private static string NameArgSig (MethodInfo mi)
-            {
-                StringBuilder sb = new StringBuilder ();
-                sb.Append (mi.Name);
-                sb.Append ('(');
-                ParameterInfo[] mps = mi.GetParameters ();
-                for (int i = 2; i < mps.Length; i ++)
-                {
-                    ParameterInfo pi = mps[i];
-                    if (i > 2) sb.Append (',');
-                    sb.Append (ParamType (pi.ParameterType));
-                }
-                sb.Append (')');
-                return sb.ToString ();
-            }
-
-            // script-visible return type
-            // note that although we support void, the comms stuff does not
-            private static TokenType RetType (MethodInfo mi)
-            {
-                Type rt = mi.ReturnType;
-                if (rt == typeof (float))                    return new TokenTypeFloat (null);
-                if (rt == typeof (int))                      return new TokenTypeInt   (null);
-                if (rt == typeof (object[]))                 return new TokenTypeList  (null);
-                if (rt == typeof (OpenMetaverse.UUID))       return new TokenTypeKey   (null);
-                if (rt == typeof (OpenMetaverse.Quaternion)) return new TokenTypeRot   (null);
-                if (rt == typeof (string))                   return new TokenTypeStr   (null);
-                if (rt == typeof (OpenMetaverse.Vector3))    return new TokenTypeVec   (null);
-                if (rt == null || rt == typeof (void))       return new TokenTypeVoid  (null);
-                throw new Exception ("unsupported return type " + rt.Name);
-            }
-
-            // script-visible parameter type
-            private static string ParamType (Type t)
-            {
-                if (t == typeof (float))                    return "float";
-                if (t == typeof (int))                      return "integer";
-                if (t == typeof (OpenMetaverse.UUID))       return "key";
-                if (t == typeof (object[]))                 return "list";
-                if (t == typeof (OpenMetaverse.Quaternion)) return "rotation";
-                if (t == typeof (string))                   return "string";
-                if (t == typeof (OpenMetaverse.Vector3))    return "vector";
-                throw new Exception ("unsupported parameter type " + t.Name);
-            }
-
-            /**
-             * @brief Called by the compiler to generate a call to the comms function.
-             * @param scg = which script is being compiled
-             * @param errorAt = where in the source code the call is being made (for error messages)
-             * @param result = a temp location to put the return value in if any
-             * @param args = array of script-visible arguments being passed to the function
-             */
-            public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
-            {
-                 // Set up 'this' pointer for modInvoker?() = value from ApiManager.CreateApi("MOD").
-                scg.PushXMRInst ();
-                scg.ilGen.Emit (errorAt, OpCodes.Castclass, xmrInstModApiCtxField.DeclaringType);
-                scg.ilGen.Emit (errorAt, OpCodes.Ldfld, xmrInstModApiCtxField);
-
-                 // Set up 'fname' argument to modInvoker?() = name of the function to be called.
-                scg.ilGen.Emit (errorAt, OpCodes.Ldstr, methName);
-
-                 // Set up 'parms' argument to modInvoker?() = object[] of the script-visible parameters,
-                 // in their LSL-wrapped form.  Of course, the modInvoker?() method will malloc yet another 
-                 // object[] and type-convert these parameters one-by-one with another round of unwrapping 
-                 // and wrapping.
-                 // Types allowed in this object[]:
-                 //    LSL_Float, LSL_Integer, LSL_Key, LSL_List, LSL_Rotation, LSL_String, LSL_Vector
-
-                int nargs = args.Length;
-                scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, nargs);
-                scg.ilGen.Emit (errorAt, OpCodes.Newarr, typeof (object));
-
-                for (int i = 0; i < nargs; i ++)
-                {
-                    scg.ilGen.Emit (errorAt, OpCodes.Dup);
-                    scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, i);
-
-                    // get location and type of argument
-                    CompValu arg = args[i];
-                    TokenType argtype = arg.type;
-
-                    // if already in a form acceptable to modInvoker?(),
-                    // just push it to the stack and convert to object
-                    // by boxing it if necessary
-
-                    // but if something like a double, int, string, etc
-                    // push to stack converting to the LSL-wrapped type
-                    // then convert to object by boxing if necessary
-
-                    Type boxit = null;
-                    if (argtype is TokenTypeLSLFloat)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_Float);
-                    }
-                    else if (argtype is TokenTypeLSLInt)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_Integer);
-                    }
-                    else if (argtype is TokenTypeLSLKey)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_Key);
-                    }
-                    else if (argtype is TokenTypeList)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_List);
-                    }
-                    else if (argtype is TokenTypeRot)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_Rotation);
-                    }
-                    else if (argtype is TokenTypeLSLString)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_String);
-                    }
-                    else if (argtype is TokenTypeVec)
-                    {
-                        args[i].PushVal (scg, errorAt);
-                        boxit = typeof (LSL_Vector);
-                    }
-                    else if (argtype is TokenTypeFloat)
-                    {
-                        args[i].PushVal (scg, errorAt, new TokenTypeLSLFloat (argtype));
-                        boxit = typeof (LSL_Float);
-                    }
-                    else if (argtype is TokenTypeInt)
-                    {
-                        args[i].PushVal (scg, errorAt, new TokenTypeLSLInt (argtype));
-                        boxit = typeof (LSL_Integer);
-                    }
-                    else if (argtype is TokenTypeKey)
-                    {
-                        args[i].PushVal (scg, errorAt, new TokenTypeLSLKey (argtype));
-                        boxit = typeof (LSL_Key);
-                    }
-                    else if (argtype is TokenTypeStr)
-                    {
-                        args[i].PushVal (scg, errorAt, new TokenTypeLSLString (argtype));
-                        boxit = typeof (LSL_String);
-                    }
-                    else
-                        throw new Exception ("unsupported arg type " + argtype.GetType ().Name);
-
-                    if (boxit.IsValueType)
-                        scg.ilGen.Emit (errorAt, OpCodes.Box, boxit);
-
-                    // pop the object into the object[]
-                    scg.ilGen.Emit (errorAt, OpCodes.Stelem, typeof (object));
-                }
-
-                 // Call the modInvoker?() method.
-                 // It leaves an LSL-wrapped type on the stack.
-                if (modInvokerMeth.IsVirtual)
-                    scg.ilGen.Emit (errorAt, OpCodes.Callvirt, modInvokerMeth);
-                else
-                    scg.ilGen.Emit (errorAt, OpCodes.Call, modInvokerMeth);
-
-                 // The 3rd arg to Pop() is the type on the stack, 
-                 // ie, what modInvoker?() actually returns.
-                 // The Pop() method will wrap/unwrap as needed.
-                Type retSysType = modInvokerMeth.ReturnType;
-                if (retSysType == null)
-                    retSysType = typeof (void);
-                TokenType retTokType = TokenType.FromSysType (errorAt, retSysType);
-                result.Pop (scg, errorAt, retTokType);
-            }
-        }
-
-        /**
-         * @brief Called late in shutdown procedure,
-         *        after the 'Shutting down..." message.
-         */
-        public void RemoveRegion(Scene scene)
-        {
-            if (!m_Enabled)
-                return;
-
-            TraceCalls("[XMREngine]: XMREngine.RemoveRegion({0})", scene.RegionInfo.RegionName);
-
-             // Write script states out to .state files so it will be
-             // available when the region is restarted.
-            DoMaintenance(null, null);
-
-             // Stop executing script threads and wait for final
-             // one to finish (ie, script gets to CheckRun() call).
-            m_Exiting = true;
-
-            m_Scene.EventManager.OnFrame -= OnFrame;
-            m_Scene.EventManager.OnRezScript -= OnRezScript;
-            m_Scene.EventManager.OnRemoveScript -= OnRemoveScript;
-            m_Scene.EventManager.OnScriptReset -= OnScriptReset;
-            m_Scene.EventManager.OnStartScript -= OnStartScript;
-            m_Scene.EventManager.OnStopScript -= OnStopScript;
-            m_Scene.EventManager.OnGetScriptRunning -= OnGetScriptRunning;
-            m_Scene.EventManager.OnShutdown -= OnShutdown;
-
-            for (int i = 0; i < numThreadScriptWorkers; i ++)
-            {
-                XMRScriptThread scriptThread = m_ScriptThreads[i];
-                if (scriptThread != null)
-                {
-                    scriptThread.WakeUpScriptThread();
-                    Monitor.PulseAll (m_WakeUpLock);
-                    scriptThread.Terminate();
-                    m_ScriptThreads[i] = null;
-                }
-            }
-
-            if (m_SleepThread != null)
-            {
-                lock (m_SleepQueue)
-                {
-                    Monitor.PulseAll (m_SleepQueue);
-                }
-                if(!m_SleepThread.Join(250))
-                    m_SleepThread.Abort();
-                m_SleepThread = null;
-            }
-
-            m_Enabled = false;
-            m_Scene = null;
-        }
-
-        public void RegionLoaded(Scene scene)
-        {
-            if (!m_Enabled)
-                return;
-
-            TraceCalls("[XMREngine]: XMREngine.RegionLoaded({0})", scene.RegionInfo.RegionName);
-
-            m_Scene.EventManager.OnFrame += OnFrame;
-            m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
-            m_Scene.EventManager.OnScriptReset += OnScriptReset;
-            m_Scene.EventManager.OnStartScript += OnStartScript;
-            m_Scene.EventManager.OnStopScript += OnStopScript;
-            m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
-            m_Scene.EventManager.OnShutdown += OnShutdown;
-
-            InitEvents();
-        }
-
-        public void StartProcessing()
-        {
-            m_log.Debug ("[XMREngine]: StartProcessing entry");
-            m_Scene.EventManager.TriggerEmptyScriptCompileQueue (0, "");
-            m_StartProcessing = true;
-            for (int i = 0; i < numThreadScriptWorkers; i ++) {
-                WakeUpOne();
-            }
-            m_log.Debug ("[XMREngine]: StartProcessing return");
-        }
-
-        public void Close()
-        {
-            TraceCalls("[XMREngine]: XMREngine.Close()");
-        }
-
-        private void RunTest (string module, string[] args)
-        {
-            if (args.Length < 2)
-            {
-                m_log.Info ("[XMREngine]: missing command, try 'xmr help'");
-                return;
-            }
-
-            switch (args[1])
-            {
-                case "cvv":
-                    switch (args.Length)
-                    {
-                        case 2:
-                            m_log.InfoFormat ("[XMREngine]: compiled version value = {0}", 
-                                    ScriptCodeGen.COMPILED_VERSION_VALUE);
-                            break;
-
-                        case 3:
-                            try
-                            {
-                                ScriptCodeGen.COMPILED_VERSION_VALUE = Convert.ToInt32 (args[2]);
-                            }
-                            catch
-                            {
-                                m_log.Error ("[XMREngine]: bad/missing version number");
-                            }
-                            break;
-
-                        default:
-                            m_log.Error ("[XMREngine]: xmr cvv [<new_compiled_version_value>]");
-                            break;
-                    }
-                    break;
-
-                case "echo":
-                    for (int i = 0; i < args.Length; i ++)
-                        m_log.Info ("[XMREngine]: echo[" + i + "]=<" + args[i] + ">");
-
-                    break;
-
-                case "gc":
-                    GC.Collect();
-                    break;
-
-                case "help":
-                case "?": 
-                    m_log.Info ("[XMREngine]: xmr cvv [<newvalue>] - show/set compiled version value");
-                    m_log.Info ("[XMREngine]: xmr gc");
-                    m_log.Info ("[XMREngine]: xmr ls [-help ...]");
-                    m_log.Info ("[XMREngine]: xmr mvv [<newvalue>] - show/set migration version value");
-                    m_log.Info ("[XMREngine]: xmr pev [-help ...] - post event");
-                    m_log.Info ("[XMREngine]: xmr reset [-help ...]");
-                    m_log.Info ("[XMREngine]: xmr resume - resume script processing");
-                    m_log.Info ("[XMREngine]: xmr suspend - suspend script processing");
-                    m_log.Info ("[XMREngine]: xmr tracecalls [yes | no]");
-                    m_log.Info ("[XMREngine]: xmr verbose [yes | no]");
-                    break;
-
-                case "ls":
-                    XmrTestLs (args, 2);
-                    break;
-
-                case "mvv":
-                    switch (args.Length)
-                    {
-                        case 2:
-                            m_log.InfoFormat ("[XMREngine]: migration version value = {0}", 
-                                    XMRInstance.migrationVersion);
-                            break;
-
-                        case 3:
-                            try
-                            {
-                                int mvv = Convert.ToInt32 (args[2]);
-                                if ((mvv < 0) || (mvv > 255)) throw new Exception ("out of range");
-                                XMRInstance.migrationVersion = (byte) mvv;
-                            }
-                            catch (Exception e)
-                            {
-                                m_log.Error ("[XMREngine]: bad/missing version number (" + e.Message + ")");
-                            }
-                            break;
-
-                        default:
-                            m_log.Error ("[XMREngine]: xmr mvv [<new_migration_version_value>]");
-                            break;
-                    }
-                    break;
-
-                case "pev":
-                    XmrTestPev (args, 2);
-                    break;
-
-                case "reset":
-                    XmrTestReset (args, 2);
-                    break;
-
-                case "resume":
-                    m_log.Info ("[XMREngine]: resuming scripts");
-                    m_SuspendScriptThreadFlag = false;
-                    for (int i = 0; i < numThreadScriptWorkers; i ++)
-                         m_ScriptThreads[i].WakeUpScriptThread();
-                    Monitor.PulseAll(m_WakeUpLock);
-                    break;
-
-                case "suspend":
-                    m_log.Info ("[XMREngine]: suspending scripts");
-                    m_SuspendScriptThreadFlag = true;
-                    for (int i = 0; i < numThreadScriptWorkers; i ++)
-                        m_ScriptThreads[i].WakeUpScriptThread();
-                    Monitor.PulseAll(m_WakeUpLock);
-                    break;
-
-                case "tracecalls":
-                    if (args.Length > 2)
-                        m_TraceCalls = (args[2][0] & 1) != 0;
-                    m_log.Info ("[XMREngine]: tracecalls " + (m_TraceCalls ? "yes" : "no"));
-                    break;
-
-                case "verbose":
-                    if (args.Length > 2)
-                        m_Verbose = (args[2][0] & 1) != 0;
-                    m_log.Info ("[XMREngine]: verbose " + (m_Verbose ? "yes" : "no"));
-                    break;
-
-                default:
-                    m_log.Error ("[XMREngine]: unknown command " + args[1] + ", try 'xmr help'");
-                    break;
-            }
-        }
-
-        // Not required when not using IScriptInstance
-        //
-        public IScriptWorkItem QueueEventHandler(object parms)
-        {
-            return null;
-        }
-
-        public Scene World
-        {
-            get { return m_Scene; }
-        }
-
-        public IScriptModule ScriptModule
-        {
-            get { return this; }
-        }
-
-        public void SaveAllState()
-        {
-            m_log.Error("[XMREngine]: XMREngine.SaveAllState() called!!");
-        }
-
-#pragma warning disable 0067
-        public event ScriptRemoved OnScriptRemoved;
-        public event ObjectRemoved OnObjectRemoved;
-#pragma warning restore 0067
-
-        // Events targeted at a specific script
-        // ... like listen() for an llListen() call
-        //
-        public bool PostScriptEvent(UUID itemID, EventParams parms)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null) return false;
-
-            TraceCalls("[XMREngine]: XMREngine.PostScriptEvent({0},{1})", itemID.ToString(), parms.EventName);
-
-            instance.PostEvent(parms);
-            return true;
-        }
-
-        // Events targeted at all scripts in the given prim.
-        //   localID = which prim
-        //   parms   = event to post
-        //
-        public bool PostObjectEvent (uint localID, EventParams parms)
-        {
-            SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
-
-            if (part == null)
-                return false;
-
-            TraceCalls("[XMREngine]: XMREngine.PostObjectEvent({0},{1})", localID.ToString(), parms.EventName);
-
-             // In SecondLife, attach events go to all scripts of all prims
-             // in a linked object.  So here we duplicate that functionality,
-             // as all we ever get is a single attach event for the whole
-             // object.
-            if (parms.EventName == "attach")
-            {
-                bool posted = false;
-                foreach (SceneObjectPart primpart in part.ParentGroup.Parts)
-                {
-                    posted |= PostPrimEvent (primpart, parms);
-                }
-                return posted;
-            }
-
-             // Other events go to just the scripts in that prim.
-            return PostPrimEvent (part, parms);
-        }
-
-        private bool PostPrimEvent (SceneObjectPart part, EventParams parms)
-        {
-            UUID partUUID = part.UUID;
-
-             // Get list of script instances running in the object.
-            XMRInstance[] objInstArray;
-            lock (m_InstancesDict)
-            {
-                if (!m_ObjectInstArray.TryGetValue (partUUID, out objInstArray))
-                    return false;
-
-                if (objInstArray == null)
-                {
-                    objInstArray = RebuildObjectInstArray (partUUID);
-                    m_ObjectInstArray[partUUID] = objInstArray;
-                }
-            }
-
-             // Post event to all script instances in the object.
-            if (objInstArray.Length <= 0) return false;
-            foreach (XMRInstance inst in objInstArray)
-                inst.PostEvent (parms);
-
-            return true;
-        }
-
-        public DetectParams GetDetectParams(UUID itemID, int number)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null)
-                return null;
-            return instance.GetDetectParams(number);
-        }
-
-        public void SetMinEventDelay(UUID itemID, double delay)
-        {
-        }
-
-        public int GetStartParameter(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null)
-                return 0;
-            return instance.StartParam;
-        }
-
-        // This is the "set running" method
-        //
-        public void SetScriptState(UUID itemID, bool state, bool self)
-        {
-            SetScriptState (itemID, state);
-        }
-        public void SetScriptState(UUID itemID, bool state)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.Running = state;
-        }
-
-        // Control display of the "running" checkbox
-        //
-        public bool GetScriptState(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null)
-                return false;
-            return instance.Running;
-        }
-
-        public void SetState(UUID itemID, string newState)
-        {
-            TraceCalls("[XMREngine]: XMREngine.SetState({0},{1})", itemID.ToString(), newState);
-        }
-
-        public void ApiResetScript(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.ApiReset();
-        }
-
-        public void ResetScript(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-            {
-                IUrlModule urlModule = m_Scene.RequestModuleInterface<IUrlModule>();
-                if (urlModule != null)
-                    urlModule.ScriptRemoved(itemID);
-
-                instance.Reset();
-            }
-        }
-
-        public IConfig Config
-        {
-            get { return m_Config; }
-        }
-
-        public IConfigSource ConfigSource
-        {
-            get { return m_ConfigSource; }
-        }
-
-        public string ScriptEngineName
-        {
-            get { return "XMREngine"; }
-        }
-
-        public IScriptApi GetApi(UUID itemID, string name)
-        {
-            FieldInfo fi;
-            if (!m_XMRInstanceApiCtxFieldInfos.TryGetValue (name, out fi))
-                return null;
-            XMRInstance inst = GetInstance (itemID);
-            if (inst == null) return null;
-            return (IScriptApi)fi.GetValue (inst);
-        }
-
-        /**
-         * @brief Get script's current state as an XML string
-         *        - called by "Take", "Take Copy" and when object deleted (ie, moved to Trash)
-         *        This includes the .state file
-         */
-        public string GetXMLState(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null)
-                return String.Empty;
-
-            TraceCalls("[XMREngine]: XMREngine.GetXMLState({0})", itemID.ToString());
-
-            if (!instance.m_HasRun)
-                return String.Empty;
-
-            XmlDocument doc = new XmlDocument();
-
-            /*
-             * Set up <State Engine="XMREngine" UUID="itemID" Asset="assetID"> tag.
-             */
-            XmlElement stateN = doc.CreateElement("", "State", "");
-            doc.AppendChild(stateN);
-
-            XmlAttribute engineA = doc.CreateAttribute("", "Engine", "");
-            engineA.Value = ScriptEngineName;
-            stateN.Attributes.Append(engineA);
-
-            XmlAttribute uuidA = doc.CreateAttribute("", "UUID", "");
-            uuidA.Value = itemID.ToString();
-            stateN.Attributes.Append(uuidA);
-
-            XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
-            string assetID = instance.AssetID.ToString();
-            assetA.Value = assetID;
-            stateN.Attributes.Append(assetA);
-
-             // Get <ScriptState>...</ScriptState> item that hold's script's state.
-             // This suspends the script if necessary then takes a snapshot.
-            XmlElement scriptStateN = instance.GetExecutionState(doc);
-            stateN.AppendChild(scriptStateN);
-
-            return doc.OuterXml;
-        }
-
-        // Set script's current state from an XML string
-        // - called just before a script is instantiated
-        // So we write the .state file so the .state file will be seen when 
-        // the script is instantiated.
-        public bool SetXMLState(UUID itemID, string xml)
-        {
-            XmlDocument doc = new XmlDocument();
-
-            try
-            {
-                doc.LoadXml(xml);
-            }
-            catch
-            {
-                return false;
-            }
-            TraceCalls("[XMREngine]: XMREngine.SetXMLState({0})", itemID.ToString());
-
-            // Make sure <State Engine="XMREngine"> so we know it is in our
-            // format.
-            XmlElement stateN = (XmlElement)doc.SelectSingleNode("State");
-            if (stateN == null)
-                return false;
-
-            if (stateN.GetAttribute("Engine") != ScriptEngineName)
-                return false;
-
-            // <ScriptState>...</ScriptState> contains contents of .state file.
-            XmlElement scriptStateN = (XmlElement)stateN.SelectSingleNode("ScriptState");
-            if (scriptStateN == null)
-                return false;
-
-            string sen = stateN.GetAttribute("Engine");
-            if ((sen == null) || (sen != ScriptEngineName))
-                return false;
-
-            XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
-            assetA.Value = stateN.GetAttribute("Asset");
-            scriptStateN.Attributes.Append(assetA);
-
-            // Write out the .state file with the <ScriptState ...>...</ScriptState> XML text
-            string statePath = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
-            FileStream ss = File.Create(statePath);
-            StreamWriter sw = new StreamWriter(ss);
-            sw.Write(scriptStateN.OuterXml);
-            sw.Close();
-            ss.Close();
-
-            return true;
-        }
-
-        public bool PostScriptEvent(UUID itemID, string name, Object[] p)
-        {
-            if (!m_Enabled)
-                return false;
-
-            TraceCalls("[XMREngine]: XMREngine.PostScriptEvent({0},{1})", itemID.ToString(), name);
-
-            return PostScriptEvent(itemID, new EventParams(name, p, zeroDetectParams));
-        }
-
-        public bool PostObjectEvent(UUID itemID, string name, Object[] p)
-        {
-            if (!m_Enabled)
-                return false;
-
-            TraceCalls("[XMREngine]: XMREngine.PostObjectEvent({0},{1})", itemID.ToString(), name);
-
-            SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
-            if (part == null)
-                return false;
-
-            return PostObjectEvent(part.LocalId, new EventParams(name, p, zeroDetectParams));
-        }
-
-        // about the 3523rd entrypoint for a script to put itself to sleep
-        public void SleepScript(UUID itemID, int delay)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.Sleep (delay);
-        }
-
-        // Get a script instance loaded, compiling it if necessary
-        //
-        //  localID     = the object as a whole, may contain many scripts
-        //  itemID      = this instance of the script in this object
-        //  script      = script source code
-        //  startParam  = value passed to 'on_rez' event handler
-        //  postOnRez   = true to post an 'on_rez' event to script on load
-        //  defEngine   = default script engine
-        //  stateSource = post this event to script on load
-
-        public void OnRezScript(uint localID, UUID itemID, string script,
-                int startParam, bool postOnRez, string defEngine, int stateSource)
-        {
-            SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
-            TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
-
-            if (!m_LateInit)
-            {
-                m_LateInit = true;
-                OneTimeLateInitialization ();
-            }
-
-            TraceCalls("[XMREngine]: OnRezScript(...,{0},...)", itemID.ToString());
-
-             // Assume script uses the default engine, whatever that is.
-            string engineName = defEngine;
-
-             // Very first line might contain "//" scriptengine ":".
-            string firstline = "";
-            if (script.StartsWith("//")) {
-                int lineEnd = script.IndexOf('\n');
-                if (lineEnd > 1) firstline = script.Substring(0, lineEnd).Trim();
-                int colon = firstline.IndexOf(':');
-                if (colon >= 2) {
-                    engineName = firstline.Substring(2, colon - 2).Trim();
-                    if (engineName == "") engineName = defEngine;
-                }
-            }
-
-             // Make sure the default or requested engine is us.
-            if (engineName != ScriptEngineName) {
-
-                 // Not us, if requested engine exists, silently ignore script and let
-                 // requested engine handle it.
-                IScriptModule[] engines = m_Scene.RequestModuleInterfaces<IScriptModule> ();
-                foreach (IScriptModule eng in engines)
-                {
-                    if (eng.ScriptEngineName == engineName)
-                        return;
-                }
-
-                 // Requested engine not defined, warn on console.
-                 // Then we try to handle it if we're the default engine, else we ignore it.
-                m_log.Warn ("[XMREngine]: " + itemID.ToString() + " requests undefined/disabled engine " + engineName);
-                m_log.Info ("[XMREngine]: - " + part.GetWorldPosition ());
-                m_log.Info ("[XMREngine]: first line: " + firstline);
-                if (defEngine != ScriptEngineName)
-                {
-                    m_log.Info ("[XMREngine]: leaving it to the default script engine (" + defEngine + ") to process it");
-                    return;
-                }
-                m_log.Info ("[XMREngine]: will attempt to processing it anyway as default script engine");
-            }
-
-             // Put on object/instance lists.
-            XMRInstance instance   = (XMRInstance)Activator.CreateInstance (ScriptCodeGen.xmrInstSuperType);
-            instance.m_LocalID     = localID;
-            instance.m_ItemID      = itemID;
-            instance.m_SourceCode  = script;
-            instance.m_StartParam  = startParam;
-            instance.m_PostOnRez   = postOnRez;
-            instance.m_StateSource = (StateSource)stateSource;
-            instance.m_Part        = part;
-            instance.m_PartUUID    = part.UUID;
-            instance.m_Item        = item;
-            instance.m_DescName    = part.Name + ":" + item.Name;
-            instance.m_IState      = XMRInstState.CONSTRUCT;
-
-            lock (m_InstancesDict)
-            {
-                m_LockedDict = "RegisterInstance";
-
-                // Insert on internal list of all scripts being handled by this engine instance.
-                m_InstancesDict[instance.m_ItemID] = instance;
-
-                // Insert on internal list of all scripts being handled by this engine instance
-                // that are part of the object.
-                List<UUID> itemIDList;
-                if (!m_ObjectItemList.TryGetValue(instance.m_PartUUID, out itemIDList))
-                {
-                    itemIDList = new List<UUID>();
-                    m_ObjectItemList[instance.m_PartUUID] = itemIDList;
-                }
-                if (!itemIDList.Contains(instance.m_ItemID))
-                {
-                    itemIDList.Add(instance.m_ItemID);
-                    m_ObjectInstArray[instance.m_PartUUID] = null;
-                }
-
-                m_LockedDict = "~RegisterInstance";
-            }
-
-             // Compile and load it.
-            lock (m_ScriptErrors)
-                m_ScriptErrors.Remove (instance.m_ItemID);
-
-            LoadThreadWork (instance);
-        }
-
-        /**
-         * @brief This routine instantiates one script.
-         */
-        private void LoadThreadWork (XMRInstance instance)
-        {
-             // Compile and load the script in memory.
-
-            ArrayList errors = new ArrayList();
-            Exception initerr = null;
-            try
-            {
-                instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
-            }
-            catch (Exception e1)
-            {
-                initerr = e1;
-            }
-            if ((initerr != null) && !instance.m_ForceRecomp)
-            {
-                UUID itemID = instance.m_ItemID;
-                Verbose ("[XMREngine]: {0}/{2} first load failed ({1}), retrying after recompile", 
-                        itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
-                Verbose ("[XMREngine]:\n{0}", initerr.ToString ());
-                initerr = null;
-                errors = new ArrayList();
-                instance.m_ForceRecomp = true;
-                try
-                {
-                    instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
-                }
-                catch (Exception e2)
-                {
-                    initerr = e2;
-                }
-            }
-            if (initerr != null)
-            {
-                UUID itemID = instance.m_ItemID;
-                Verbose ("[XMREngine]: Error starting script {0}/{2}: {1}",
-                                  itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
-                if (initerr.Message != "compilation errors")
-                {
-                    Verbose ("[XMREngine]: - " + instance.m_Part.GetWorldPosition () + " " + instance.m_DescName);
-                    Verbose ("[XMREngine]:   exception:\n{0}", initerr.ToString());
-                }
-
-                OnRemoveScript (0, itemID);
-
-                 // Post errors where GetScriptErrors() can see them.
-
-                if (errors.Count == 0)
-                    errors.Add(initerr.Message);
-                else
-                {
-                    foreach (Object err in errors)
-                    {
-                        if (m_ScriptDebug)
-                            m_log.DebugFormat ("[XMREngine]:   {0}", err.ToString());
-                    }
-                }
-
-                lock (m_ScriptErrors)
-                    m_ScriptErrors[instance.m_ItemID] = errors;
-
-                return;
-            }
-
-             // Tell GetScriptErrors() that we have finished compiling/loading
-             // successfully (by posting a 0 element array).
-            lock (m_ScriptErrors)
-            {
-                if (instance.m_IState != XMRInstState.CONSTRUCT) throw new Exception("bad state");
-                m_ScriptErrors[instance.m_ItemID] = noScriptErrors;
-            }
-
-             // Transition from CONSTRUCT->ONSTARTQ and give to RunScriptThread().
-             // Put it on the start queue so it will run any queued event handlers,
-             // such as state_entry() or on_rez().  If there aren't any queued, it
-             // will just go to idle state when RunOne() tries to dequeue an event.
-            lock (instance.m_QueueLock)
-            {
-                if (instance.m_IState != XMRInstState.CONSTRUCT)
-                    throw new Exception("bad state");
-                instance.m_IState = XMRInstState.ONSTARTQ;
-                if (!instance.m_Running)
-                    instance.EmptyEventQueues ();
-            }
-            QueueToStart(instance);
-        }
-
-        public void OnRemoveScript(uint localID, UUID itemID)
-        {
-            TraceCalls("[XMREngine]: OnRemoveScript(...,{0})", itemID.ToString());
-
-             // Remove from our list of known scripts.
-             // After this, no more events can queue because we won't be
-             // able to translate the itemID to an XMRInstance pointer.
-
-            XMRInstance instance = null;
-            lock (m_InstancesDict)
-            {
-                m_LockedDict = "OnRemoveScript:" + itemID.ToString();
-
-                 // Tell the instance to free off everything it can.
-
-                if (!m_InstancesDict.TryGetValue(itemID, out instance))
-                {
-                    m_LockedDict = "~OnRemoveScript";
-                    return;
-                }
-
-                 // Tell it to stop executing anything.
-                instance.suspendOnCheckRunHold = true;
-
-                 // Remove it from our list of known script instances
-                 // mostly so no more events can queue to it.
-                m_InstancesDict.Remove(itemID);
-
-                List<UUID> itemIDList;
-                if (m_ObjectItemList.TryGetValue (instance.m_PartUUID, out itemIDList))
-                {
-                    itemIDList.Remove(itemID);
-                    if (itemIDList.Count == 0)
-                    {
-                        m_ObjectItemList.Remove(instance.m_PartUUID);
-                        m_ObjectInstArray.Remove(instance.m_PartUUID);
-                    }
-                    else
-                        m_ObjectInstArray[instance.m_PartUUID] = null;
-                }
-
-                 // Delete the .state file as any needed contents were fetched with GetXMLState()
-                 // and stored on the database server.
-                string stateFileName = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
-                File.Delete(stateFileName);
-
-                ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
-                if (handlerScriptRemoved != null)
-                    handlerScriptRemoved(itemID);
-
-                m_LockedDict = "~~OnRemoveScript";
-            }
-
-             // Free off its stack and fun things like that.
-             // If it is running, abort it.
-            instance.Dispose ();
-        }
-
-        public void OnScriptReset(uint localID, UUID itemID)
-        {
-            TraceCalls("[XMREngine]: XMREngine.OnScriptReset({0},{1})", localID.ToString(), itemID.ToString());
-            ResetScript(itemID);
-        }
-
-        public void OnStartScript(uint localID, UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.Running = true;
-        }
-
-        public void OnStopScript(uint localID, UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.Running = false;
-        }
-
-        public void OnGetScriptRunning(IClientAPI controllingClient,
-                UUID objectID, UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-            {
-                TraceCalls("[XMREngine]: XMREngine.OnGetScriptRunning({0},{1})", objectID.ToString(), itemID.ToString());
-
-                IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
-                if (eq == null)
-                {
-                    controllingClient.SendScriptRunningReply(objectID, itemID,
-                            instance.Running);
-                }
-                else
-                {
-                    eq.Enqueue(EventQueueHelper.ScriptRunningReplyEvent(objectID,
-                            itemID, instance.Running, true),
-                            controllingClient.AgentId);
-                }
-            }
-        }
-
-        public bool HasScript(UUID itemID, out bool running)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance == null)
-            {
-                running = true;
-                return false;
-            }
-            running = instance.Running;
-            return true;
-        }
-
-        /**
-         * @brief Called once per frame update to see if scripts have
-         *        any such work to do.
-         */
-        private void OnFrame ()
-        {
-            if (m_FrameUpdateList != null)
-            {
-                ThreadStart frameupdates;
-                lock (m_FrameUpdateLock)
-                {
-                    frameupdates = m_FrameUpdateList;
-                    m_FrameUpdateList = null;
-                }
-                frameupdates ();
-            }
-        }
-
-        /**
-         * @brief Add a one-shot delegate to list of things to do
-         *        synchronized with frame updates.
-         */
-        public void AddOnFrameUpdate (ThreadStart thunk)
-        {
-            lock (m_FrameUpdateLock)
-                m_FrameUpdateList += thunk;
-        }
-
-        /**
-         * @brief Gets called early as part of shutdown,
-         *        right after "Persisting changed objects" message.
-         */
-        public void OnShutdown()
-        {
-            TraceCalls("[XMREngine]: XMREngine.OnShutdown()");
-        }
-
-        /**
-         * @brief Queue an instance to the StartQueue so it will run.
-         *        This queue is used for instances that have just had
-         *        an event queued to them when they were previously
-         *        idle.  It must only be called by the thread that
-         *        transitioned the thread to XMRInstState.ONSTARTQ so
-         *        we don't get two threads trying to queue the same
-         *        instance to the m_StartQueue at the same time.
-         */
-        public void QueueToStart(XMRInstance inst)
-        {
-            lock (m_StartQueue)
-            {
-                if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state");
-                m_StartQueue.InsertTail(inst);
-            }
-            WakeUpOne();
-        }
-
-        public void QueueToTrunk(ThreadStart thds)
-        {
-            lock (m_WakeUpLock)
-                    m_ThunkQueue.Enqueue (thds);
-            WakeUpOne();
-        }
-
-        /**
-         * @brief A script may be sleeping, in which case we wake it.
-         */
-        public void WakeFromSleep(XMRInstance inst)
-        {
-             // Remove from sleep queue unless someone else already woke it.
-            lock (m_SleepQueue)
-            {
-                if (inst.m_IState != XMRInstState.ONSLEEPQ)
-                    return;
-
-                m_SleepQueue.Remove(inst);
-                inst.m_IState = XMRInstState.REMDFROMSLPQ;
-            }
-
-             // Put on end of list of scripts that are ready to run.
-            lock (m_YieldQueue)
-            {
-                inst.m_IState = XMRInstState.ONYIELDQ;
-                m_YieldQueue.InsertTail(inst);
-            }
-
-
-             // Make sure the OS thread is running so it will see the script.
-            WakeUpOne();
-        }
-
-        /**
-         * @brief An instance has just finished running for now,
-         *        figure out what to do with it next.
-         * @param inst = instance in question, not on any queue at the moment
-         * @param newIState = its new state
-         * @returns with instance inserted onto proper queue (if any)
-         */
-        public void HandleNewIState(XMRInstance inst, XMRInstState newIState)
-        {
-
-             // RunOne() should have left the instance in RUNNING state.
-            if (inst.m_IState != XMRInstState.RUNNING)
-                throw new Exception("bad state");
-
-
-             // Now see what RunOne() wants us to do with the instance next.
-            switch (newIState)
-            {
-
-                 // Instance has set m_SleepUntil to when it wants to sleep until.
-                 // So insert instance in sleep queue by ascending wake time.
-                 // Then wake the timer thread if this is the new first entry
-                 // so it will reset its timer.
-                case XMRInstState.ONSLEEPQ:
-                    lock (m_SleepQueue)
-                     {
-                        XMRInstance after;
-
-                        inst.m_IState = XMRInstState.ONSLEEPQ;
-                        for (after = m_SleepQueue.PeekHead(); after != null; after = after.m_NextInst)
-                        {
-                            if (after.m_SleepUntil > inst.m_SleepUntil)
-                                break;
-                        }
-                        m_SleepQueue.InsertBefore(inst, after);
-                        if (m_SleepQueue.PeekHead() == inst)
-                        {
-                            Monitor.Pulse (m_SleepQueue);
-                        }
-                    }
-                    break;
-
-                 // Instance just took a long time to run and got wacked by the
-                 // slicer.  So put on end of yield queue to let someone else
-                 // run.  If there is no one else, it will run again right away.
-                case XMRInstState.ONYIELDQ:
-                    lock (m_YieldQueue)
-                    {
-                        inst.m_IState = XMRInstState.ONYIELDQ;
-                        m_YieldQueue.InsertTail(inst);
-                    }
-                    break;
-
-                 // Instance finished executing an event handler.  So if there is
-                 // another event queued for it, put it on the start queue so it
-                 // will process the new event.  Otherwise, mark it idle and the
-                 // next event to queue to it will start it up.
-                case XMRInstState.FINISHED:
-                    Monitor.Enter(inst.m_QueueLock);
-                    if (!inst.m_Suspended && (inst.m_EventQueue.Count > 0))
-                    {
-                        Monitor.Exit(inst.m_QueueLock);
-                        lock (m_StartQueue)
-                        {
-                            inst.m_IState = XMRInstState.ONSTARTQ;
-                            m_StartQueue.InsertTail (inst);
-                        }
-                    }
-                    else
-                    {
-                        inst.m_IState = XMRInstState.IDLE;
-                        Monitor.Exit(inst.m_QueueLock);
-                    }
-                    break;
-
-                 // Its m_SuspendCount > 0.
-                 // Don't put it on any queue and it won't run.
-                 // Since it's not IDLE, even queuing an event won't start it.
-                case XMRInstState.SUSPENDED:
-                    inst.m_IState = XMRInstState.SUSPENDED;
-                    break;
-
-                 // It has been disposed of.
-                 // Just set the new state and all refs should theoretically drop off
-                 // as the instance is no longer in any list.
-                case XMRInstState.DISPOSED:
-                    inst.m_IState = XMRInstState.DISPOSED;
-                    break;
-
-                 // RunOne returned something bad.
-                default:
-                     throw new Exception("bad new state");
-            }
-        }
-
-        /**
-         * @brief Thread that moves instances from the Sleep queue to the Yield queue.
-         */
-        private void RunSleepThread()
-        {
-            double deltaTS;
-            int deltaMS;
-            XMRInstance inst;
-
-            while (true)
-            {
-                lock (m_SleepQueue)
-                {
-
-                     // Wait here until there is a script on the timer queue that has expired.
-                    while (true)
-                    {
-                        UpdateMyThread ();
-                        if (m_Exiting)
-                        {
-                            MyThreadExiting ();
-                            return;
-                        }
-                        inst = m_SleepQueue.PeekHead();
-                        if (inst == null)
-                        {
-                            Monitor.Wait (m_SleepQueue, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
-                            continue;
-                        }
-                        if (inst.m_IState != XMRInstState.ONSLEEPQ) throw new Exception("bad state");
-                        deltaTS = (inst.m_SleepUntil - DateTime.UtcNow).TotalMilliseconds;
-                        if (deltaTS <= 0.0)
-                            break;
-                        deltaMS = Int32.MaxValue;
-                        if (deltaTS < Int32.MaxValue)
-                            deltaMS = (int)deltaTS;
-                        if (deltaMS > Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2)
-                        {
-                            deltaMS = Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2;
-                        }
-                        Monitor.Wait (m_SleepQueue, deltaMS);
-                    }
-
-                     // Remove the expired entry from the timer queue.
-                    m_SleepQueue.RemoveHead();
-                    inst.m_IState = XMRInstState.REMDFROMSLPQ;
-                }
-
-                 // Post the script to the yield queue so it will run and wake a script thread to run it.
-                lock (m_YieldQueue)
-                {
-                    inst.m_IState = XMRInstState.ONYIELDQ;
-                    m_YieldQueue.InsertTail(inst);
-                }
-                WakeUpOne ();
-            }
-        }
-
-        /**
-         * @brief Thread that runs a time slicer.
-         */
-        public void Suspend(UUID itemID, int ms)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-                instance.Sleep(ms);
-        }
-
-        public void Die(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-            {
-                TraceCalls("[XMREngine]: XMREngine.Die({0})", itemID.ToString());
-                instance.Die();
-            }
-        }
-
-        /**
-         * @brief Get specific script instance for which OnRezScript()
-         *        has been called for an XMREngine script, and that
-         *        OnRemoveScript() has not been called since.
-         * @param itemID = as passed to OnRezScript() identifying a specific script instance
-         * @returns null: not one of our scripts (maybe XEngine etc)
-         *          else: points to the script instance
-         */
-        public XMRInstance GetInstance(UUID itemID)
-        {
-            XMRInstance instance;
-            lock (m_InstancesDict)
-            {
-                if (!m_InstancesDict.TryGetValue(itemID, out instance))
-                    instance = null;
-            }
-            return instance;
-        }
-
-        // Called occasionally to write script state to .state file so the
-        // script will restart from its last known state if the region crashes
-        // and gets restarted.
-        private void DoMaintenance(object source, ElapsedEventArgs e)
-        {
-            XMRInstance[] instanceArray;
-
-            lock (m_InstancesDict)
-                instanceArray = System.Linq.Enumerable.ToArray(m_InstancesDict.Values);
-
-            foreach (XMRInstance ins in instanceArray)
-            {
-                // Don't save attachments
-                if (ins.m_Part.ParentGroup.IsAttachment)
-                    continue;
-                ins.GetExecutionState(new XmlDocument());
-            }
-        }
-
-        /**
-         * @brief Retrieve errors generated by a previous call to OnRezScript().
-         *        We are guaranteed this routine will not be called before the
-         *        corresponding OnRezScript() has returned.  It blocks until the
-         *        compile has completed.
-         */
-        public ArrayList GetScriptErrors(UUID itemID)
-        {
-            ArrayList errors;
-
-            lock (m_ScriptErrors)
-            {
-                while (!m_ScriptErrors.TryGetValue (itemID, out errors))
-                {
-                    Monitor.Wait (m_ScriptErrors);
-                }
-                m_ScriptErrors.Remove (itemID);
-            }
-            return errors;
-        }
-
-        /**
-         * @brief Return a list of all script execution times.
-         */
-        public Dictionary<uint, float> GetObjectScriptsExecutionTimes ()
-        {
-            Dictionary<uint, float> topScripts = new Dictionary<uint, float> ();
-            lock (m_InstancesDict)
-            {
-                foreach (XMRInstance instance in m_InstancesDict.Values)
-                {
-                    uint rootLocalID = instance.m_Part.ParentGroup.LocalId;
-                    float oldTotal;
-                    if (!topScripts.TryGetValue (rootLocalID, out oldTotal))
-                        oldTotal = 0;
-
-                    topScripts[rootLocalID] = (float)instance.m_CPUTime + oldTotal;
-                }
-            }
-            return topScripts;
-        }
-
-        /**
-         * @brief A float the value is a representative execution time in
-         *        milliseconds of all scripts in the link set.
-         * @param itemIDs = list of scripts in the link set
-         * @returns milliseconds for all those scripts
-         */
-        public float GetScriptExecutionTime (List<UUID> itemIDs)
-        {
-            if ((itemIDs == null) || (itemIDs.Count == 0))
-                return 0;
-
-            float time = 0;
-            foreach (UUID itemID in itemIDs)
-            {
-                XMRInstance instance = GetInstance (itemID);
-                if ((instance != null) && instance.Running)
-                    time += (float) instance.m_CPUTime;
-            }
-            return time;
-        }
-
-        /**
-         * @brief Block script from dequeuing events.
-         */
-        public void SuspendScript(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-            {
-                TraceCalls("[XMREngine]: XMREngine.SuspendScript({0})", itemID.ToString());
-                instance.SuspendIt();
-            }
-        }
-
-        /**
-         * @brief Allow script to dequeue events.
-         */
-        public void ResumeScript(UUID itemID)
-        {
-            XMRInstance instance = GetInstance (itemID);
-            if (instance != null)
-            {
-                TraceCalls("[XMREngine]: XMREngine.ResumeScript({0})", itemID.ToString());
-                instance.ResumeIt();
-            }
-            else
-            {
-                // probably an XEngine script
-            }
-        }
-
-        /**
-         * @brief Rebuild m_ObjectInstArray[partUUID] from m_ObjectItemList[partUUID]
-         * @param partUUID = which object in scene to rebuild for
-         */
-        private XMRInstance[] RebuildObjectInstArray (UUID partUUID)
-        {
-            List<UUID> itemIDList = m_ObjectItemList[partUUID];
-            int n = 0;
-            foreach (UUID itemID in itemIDList)
-            {
-                if (m_InstancesDict.ContainsKey(itemID))
-                    n ++;
-            }
-            XMRInstance[] a = new XMRInstance[n];
-            n = 0;
-            foreach (UUID itemID in itemIDList)
-            {
-                if (m_InstancesDict.TryGetValue (itemID, out a[n]))
-                    n ++;
-            }
-            m_ObjectInstArray[partUUID] = a;
-            return a;
-        }
-
-        public void TraceCalls (string format, params object[] args)
-        {
-            if (m_TraceCalls)
-                m_log.DebugFormat (format, args);
-        }
-        public void Verbose (string format, params object[] args)
-        {
-            if (m_Verbose)
-                m_log.DebugFormat (format, args);
-        }
-
-        /**
-         * @brief Manage our threads.
-         */
-        public static Thread StartMyThread (ThreadStart start, string name, ThreadPriority priority)
-        {
-            m_log.Debug ("[XMREngine]: starting thread " + name);
-            Thread thread   = new Thread (start);
-            thread.Name     = name;
-            thread.Priority = priority;
-            thread.IsBackground = true;
-            thread.Start ();
-
-            Watchdog.ThreadWatchdogInfo info = new Watchdog.ThreadWatchdogInfo (thread, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS, name);
-            Watchdog.AddThread (info, name, true);
-
-            return thread;
-        }
-
-        public static void UpdateMyThread ()
-        {
-            Watchdog.UpdateThread();
-        }
-
-        public static void MyThreadExiting ()
-        {
-            Watchdog.RemoveThread(true);
-        }
-
-        public void RunScriptThread(XMRScriptThread xthd)
-        {
-            XMRInstance inst;
-            while (!m_Exiting)
-            {
-                Watchdog.UpdateThread();
-
-                /*
-                 * Handle 'xmr resume/suspend' commands.
-                 */
-                if (m_SuspendScriptThreadFlag)
-                {
-                    lock (m_WakeUpLock)
-                    {
-                        while (m_SuspendScriptThreadFlag &&
-                               !m_Exiting &&
-                               (m_ThunkQueue.Count == 0))
-                        {
-                            Monitor.Wait (m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
-                            XMREngine.UpdateMyThread ();
-                        }
-                    }
-                }
-
-                /*
-                 * Maybe there are some scripts waiting to be migrated in or out.
-                 */
-                ThreadStart thunk = null;
-                lock (m_WakeUpLock)
-                {
-                    if (m_ThunkQueue.Count > 0)
-                        thunk = m_ThunkQueue.Dequeue ();
-                }
-                if (thunk != null)
-                {
-                    inst = (XMRInstance)thunk.Target;
-                    thunk ();
-                    if (m_Exiting || m_SuspendScriptThreadFlag)
-                        continue;
-                }
-
-                if (m_StartProcessing)
-                {
-                     // If event just queued to any idle scripts
-                     // start them right away.  But only start so
-                     // many so we can make some progress on yield
-                     // queue.
-
-                    int numStarts;
-                    for (numStarts = 5; -- numStarts >= 0;)
-                    {
-                        lock (m_StartQueue)
-                        {
-                            inst = m_StartQueue.RemoveHead();
-                        }
-                        if (inst == null) break;
-                        if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state");
-                        xthd.RunInstance (inst);
-                        if (m_Exiting || m_SuspendScriptThreadFlag)
-                            continue;
-                    }
-
-                     // If there is something to run, run it
-                     // then rescan from the beginning in case
-                     // a lot of things have changed meanwhile.
-                     //
-                     // These are considered lower priority than
-                     // m_StartQueue as they have been taking at
-                     // least one quantum of CPU time and event
-                     // handlers are supposed to be quick.
-
-                    lock (m_YieldQueue)
-                    {
-                        inst = m_YieldQueue.RemoveHead();
-                    }
-                    if (inst != null)
-                    {
-                        if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state");
-                        xthd.RunInstance(inst);
-                        numStarts = -1;
-                    }
-
-                     // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
-                    if (m_Exiting || numStarts < 0)
-                        continue;
-                }
-
-                 // Nothing to do, sleep.
-                lock (m_WakeUpLock)
-                {
-                    if (!xthd.m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
-                        Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
-
-                    xthd.m_WakeUpThis = false;
-                    if ((m_WakeUpOne > 0) && (--m_WakeUpOne > 0))
-                        Monitor.Pulse (m_WakeUpLock);
-                }
-            }
-            Watchdog.RemoveThread(true);
-        }
-    }
-}

+ 0 - 2109
OpenSim/Region/ScriptEngine/XMREngine/XMRInstAbstract.cs

@@ -1,2109 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Reflection.Emit;
-using System.Text;
-using System.Threading;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public class XMRInstArrays {
-        public XMR_Array[]      iarArrays;
-        public char[]           iarChars;
-        public double[]    iarFloats;
-        public int[]            iarIntegers;
-        public LSL_List[]       iarLists;
-        public object[]         iarObjects;
-        public LSL_Rotation[]   iarRotations;
-        public string[]         iarStrings;
-        public LSL_Vector[]     iarVectors;
-        public XMRSDTypeClObj[] iarSDTClObjs;
-        public Delegate[][]     iarSDTIntfObjs;
-
-        private XMRInstAbstract instance;
-        private int heapUse;
-
-        private static readonly XMR_Array[]      noArrays      = new XMR_Array[0];
-        private static readonly char[]           noChars       = new char[0];
-        private static readonly double[]         noFloats      = new double[0];
-        private static readonly int[]            noIntegers    = new int[0];
-        private static readonly LSL_List[]       noLists       = new LSL_List[0];
-        private static readonly object[]         noObjects     = new object[0];
-        private static readonly LSL_Rotation[]   noRotations   = new LSL_Rotation[0];
-        private static readonly string[]         noStrings     = new string[0];
-        private static readonly LSL_Vector[]     noVectors     = new LSL_Vector[0];
-        private static readonly XMRSDTypeClObj[] noSDTClObjs   = new XMRSDTypeClObj[0];
-        private static readonly Delegate[][]     noSDTIntfObjs = new Delegate[0][];
-
-        public XMRInstArrays (XMRInstAbstract inst)
-        {
-            instance = inst;
-        }
-
-        ~XMRInstArrays ()
-        {
-            heapUse = instance.UpdateHeapUse (heapUse, 0);
-        }
-
-        public void AllocVarArrays (XMRInstArSizes ars)
-        {
-            ClearOldArrays ();
-
-            heapUse = instance.UpdateHeapUse (heapUse,
-                ars.iasChars       * HeapTrackerObject.HT_CHAR +
-                ars.iasFloats      * HeapTrackerObject.HT_SFLT +
-                ars.iasIntegers    * HeapTrackerObject.HT_INT +
-                ars.iasRotations   * HeapTrackerObject.HT_ROT +
-                ars.iasVectors     * HeapTrackerObject.HT_VEC +
-                ars.iasSDTIntfObjs * HeapTrackerObject.HT_DELE);
-
-            iarArrays      = (ars.iasArrays      > 0) ? new XMR_Array     [ars.iasArrays]        : noArrays;
-            iarChars       = (ars.iasChars       > 0) ? new char          [ars.iasChars]         : noChars;
-            iarFloats      = (ars.iasFloats      > 0) ? new double        [ars.iasFloats]        : noFloats;
-            iarIntegers    = (ars.iasIntegers    > 0) ? new int           [ars.iasIntegers]      : noIntegers;
-            iarLists       = (ars.iasLists       > 0) ? new LSL_List      [ars.iasLists]         : noLists;
-            iarObjects     = (ars.iasObjects     > 0) ? new object        [ars.iasObjects]       : noObjects;
-            iarRotations   = (ars.iasRotations   > 0) ? new LSL_Rotation  [ars.iasRotations]     : noRotations;
-            iarStrings     = (ars.iasStrings     > 0) ? new string        [ars.iasStrings]       : noStrings;
-            iarVectors     = (ars.iasVectors     > 0) ? new LSL_Vector    [ars.iasVectors]       : noVectors;
-            iarSDTClObjs   = (ars.iasSDTClObjs   > 0) ? new XMRSDTypeClObj[ars.iasSDTClObjs]     : noSDTClObjs;
-            iarSDTIntfObjs = (ars.iasSDTIntfObjs > 0) ? new Delegate      [ars.iasSDTIntfObjs][] : noSDTIntfObjs;
-        }
-
-        /**
-         * @brief Do not write directly to iarLists[index], rather use this method.
-         */
-        public void PopList (int index, LSL_List lis)
-        {
-            LSL_List old = iarLists[index];
-            int newheapuse = heapUse + HeapTrackerList.Size (lis) - HeapTrackerList.Size (old);
-            heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
-            iarLists[index] = lis;
-        }
-
-        /**
-         * @brief Do not write directly to iarObjects[index], rather use this method.
-         */
-        public void PopObject (int index, object obj)
-        {
-            object old = iarObjects[index];
-            int newheapuse = heapUse + HeapTrackerObject.Size (obj) - HeapTrackerObject.Size (old);
-            heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
-            iarObjects[index] = obj;
-        }
-
-        /**
-         * @brief Do not write directly to iarStrings[index], rather use this method.
-         */
-        public void PopString (int index, string str)
-        {
-            string old = iarStrings[index];
-            int newheapuse = heapUse + HeapTrackerString.Size (str) - HeapTrackerString.Size (old);
-            heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
-            iarStrings[index] = str;
-        }
-
-        /**
-         * @brief Write all arrays out to a file.
-         */
-        public delegate void Sender (object value);
-        public void SendArrays (Sender sender)
-        {
-            sender (iarArrays);
-            sender (iarChars);
-            sender (iarFloats);
-            sender (iarIntegers);
-            sender (iarLists);
-            sender (iarObjects);
-            sender (iarRotations);
-            sender (iarStrings);
-            sender (iarVectors);
-            sender (iarSDTClObjs);
-            sender (iarSDTIntfObjs);
-        }
-
-        /**
-         * @brief Read all arrays in from a file.
-         */
-        public delegate object Recver ();
-        public void RecvArrays (Recver recver)
-        {
-            ClearOldArrays ();
-
-            iarArrays           = (XMR_Array[])      recver ();
-            char[] chrs         = (char[])           recver ();
-            double[] flts       = (double[])    recver ();
-            int[] ints          = (int[])            recver ();
-            LSL_List[] liss     = (LSL_List[])       recver ();
-            object[] objs       = (object[])         recver ();
-            LSL_Rotation[] rots = (LSL_Rotation[])   recver ();
-            string[] strs       = (string[])         recver ();
-            LSL_Vector[] vecs   = (LSL_Vector[])     recver ();
-            iarSDTClObjs        = (XMRSDTypeClObj[]) recver ();
-            Delegate[][] dels   = (Delegate[][])     recver ();
-
-            int newheapuse = heapUse;
-
-            // value types simply are the size of the value * number of values
-            newheapuse += chrs.Length * HeapTrackerObject.HT_CHAR;
-            newheapuse += flts.Length * HeapTrackerObject.HT_SFLT;
-            newheapuse += ints.Length * HeapTrackerObject.HT_INT;
-            newheapuse += rots.Length * HeapTrackerObject.HT_ROT;
-            newheapuse += vecs.Length * HeapTrackerObject.HT_VEC;
-            newheapuse += dels.Length * HeapTrackerObject.HT_DELE;
-
-            // lists, objects, strings are the sum of the size of each element
-            foreach (LSL_List lis in liss)
-                newheapuse += HeapTrackerList.Size (lis);
-
-            foreach (object obj in objs)
-                newheapuse += HeapTrackerObject.Size (obj);
-
-            foreach (string str in strs)
-                newheapuse += HeapTrackerString.Size (str);
-
-            // others (XMR_Array, XMRSDTypeClObj) keep track of their own heap usage
-
-            // update script heap usage, throwing an exception before finalizing changes
-            heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
-
-            iarChars       = chrs;
-            iarFloats      = flts;
-            iarIntegers    = ints;
-            iarLists       = liss;
-            iarObjects     = objs;
-            iarRotations   = rots;
-            iarStrings     = strs;
-            iarVectors     = vecs;
-            iarSDTIntfObjs = dels;
-        }
-
-        private void ClearOldArrays ()
-        {
-            int newheapuse = heapUse;
-
-            iarArrays = null;
-            if (iarChars != null)
-            {
-                newheapuse -= iarChars.Length * HeapTrackerObject.HT_CHAR;
-                iarChars = null;
-            }
-            if (iarFloats != null)
-            {
-                newheapuse -= iarFloats.Length * HeapTrackerObject.HT_SFLT;
-                iarFloats = null;
-            }
-            if (iarIntegers != null)
-            {
-                newheapuse -= iarIntegers.Length * HeapTrackerObject.HT_INT;
-                iarIntegers = null;
-            }
-            if (iarLists != null)
-            {
-                foreach (LSL_List lis in iarLists)
-                    newheapuse -= HeapTrackerList.Size (lis);
-
-                iarLists = null;
-            }
-            if (iarObjects != null)
-            {
-                foreach (object obj in iarObjects)
-                    newheapuse -= HeapTrackerObject.Size (obj);
-
-                iarObjects = null;
-            }
-            if (iarRotations != null)
-            {
-                newheapuse -= iarRotations.Length * HeapTrackerObject.HT_ROT;
-                iarRotations = null;
-            }
-            if (iarStrings != null)
-            {
-                foreach (string str in iarStrings)
-                    newheapuse -= HeapTrackerString.Size (str);
-
-                iarStrings = null;
-            }
-            if (iarVectors != null)
-            {
-                newheapuse -= iarVectors.Length * HeapTrackerObject.HT_VEC;
-                iarVectors = null;
-            }
-            iarSDTClObjs = null;
-            if (iarSDTIntfObjs != null)
-            {
-                newheapuse -= iarSDTIntfObjs.Length * HeapTrackerObject.HT_DELE;
-                iarSDTIntfObjs = null;
-            }
-
-            heapUse = instance.UpdateHeapUse (heapUse, newheapuse);
-        }
-    }
-
-    public class XMRInstArSizes
-    {
-        public int iasArrays;
-        public int iasChars;
-        public int iasFloats;
-        public int iasIntegers;
-        public int iasLists;
-        public int iasObjects;
-        public int iasRotations;
-        public int iasStrings;
-        public int iasVectors;
-        public int iasSDTClObjs;
-        public int iasSDTIntfObjs;
-
-        public void WriteAsmFile (TextWriter asmFileWriter, string label)
-        {
-            asmFileWriter.WriteLine ("  {0}Arrays       {1}", label, iasArrays);
-            asmFileWriter.WriteLine ("  {0}Chars        {1}", label, iasChars);
-            asmFileWriter.WriteLine ("  {0}Floats       {1}", label, iasFloats);
-            asmFileWriter.WriteLine ("  {0}Integers     {1}", label, iasIntegers);
-            asmFileWriter.WriteLine ("  {0}Lists        {1}", label, iasLists);
-            asmFileWriter.WriteLine ("  {0}Objects      {1}", label, iasObjects);
-            asmFileWriter.WriteLine ("  {0}Rotations    {1}", label, iasRotations);
-            asmFileWriter.WriteLine ("  {0}Strings      {1}", label, iasStrings);
-            asmFileWriter.WriteLine ("  {0}Vectors      {1}", label, iasVectors);
-            asmFileWriter.WriteLine ("  {0}SDTClObjs    {1}", label, iasSDTClObjs);
-            asmFileWriter.WriteLine ("  {0}SDTIntfObjs  {1}", label, iasSDTIntfObjs);
-        }
-        public void WriteToFile (BinaryWriter objFileWriter)
-        {
-            objFileWriter.Write (iasArrays);
-            objFileWriter.Write (iasChars);
-            objFileWriter.Write (iasFloats);
-            objFileWriter.Write (iasIntegers);
-            objFileWriter.Write (iasLists);
-            objFileWriter.Write (iasObjects);
-            objFileWriter.Write (iasRotations);
-            objFileWriter.Write (iasStrings);
-            objFileWriter.Write (iasVectors);
-            objFileWriter.Write (iasSDTClObjs);
-            objFileWriter.Write (iasSDTIntfObjs);
-        }
-        public void ReadFromFile (BinaryReader objFileReader)
-        {
-            iasArrays      = objFileReader.ReadInt32 ();
-            iasChars       = objFileReader.ReadInt32 ();
-            iasFloats      = objFileReader.ReadInt32 ();
-            iasIntegers    = objFileReader.ReadInt32 ();
-            iasLists       = objFileReader.ReadInt32 ();
-            iasObjects     = objFileReader.ReadInt32 ();
-            iasRotations   = objFileReader.ReadInt32 ();
-            iasStrings     = objFileReader.ReadInt32 ();
-            iasVectors     = objFileReader.ReadInt32 ();
-            iasSDTClObjs   = objFileReader.ReadInt32 ();
-            iasSDTIntfObjs = objFileReader.ReadInt32 ();
-        }
-    }
-
-    public class XMRStackFrame
-    {
-        public XMRStackFrame nextSF;
-        public string funcName;
-        public int callNo;
-        public object[] objArray;
-    }
-
-    /*
-     * Contains only items required by the stand-alone compiler
-     * so the compiler doesn't need to pull in all of OpenSim.
-     *
-     * Inherit from ScriptBaseClass so we can be used as 'this'
-     * parameter for backend-API calls, eg llSay().
-     */
-    public abstract class XMRInstAbstract : ScriptBaseClass
-    {
-        public const int CallMode_NORMAL  = 0;  // when function is called, it proceeds normally
-        public const int CallMode_SAVE    = 1;  // StackSaveException() was thrown, push args/locals to stackFrames
-        public const int CallMode_RESTORE = 2;  // when function is called, it pops state from stackFrames
-
-        public bool suspendOnCheckRunHold;  // suspend script execution until explicitly set false
-        public bool suspendOnCheckRunTemp;  // suspend script execution for single step only
-        public int stackLimit;              // stack must have at least this many bytes free on entry to functions
-
-        public ScriptObjCode m_ObjCode;     // script object code this instance was created from
-
-        public object[] ehArgs;             // event handler argument array
-        public bool doGblInit = true;       // default state_entry() needs to initialize global variables
-        public int stateCode = 0;           // state the script is in (0 = 'default')
-        public int newStateCode = -1;       // if >= 0, in the middle of exiting 'stateCode' and entering 'newStateCode'
-        public ScriptEventCode eventCode = ScriptEventCode.None;
-                                            // what event handler is executing (or None if not)
-
-        public int callMode = CallMode_NORMAL;
-                                            // to capture stack frames on stackFrames:
-                                            //    set to CallMode_SAVE just before throwing StackSaveException()
-                                            //    from within CheckRun() and cleared to CallMode_NORMAL when
-                                            //    the exception is caught
-                                            // to restore stack frames from stackFrames:
-                                            //    set to CallMode_RESTORE just before calling CallSEH() and 
-                                            //    cleared to CallMode_NORMAL by CheckRun()
-        public XMRStackFrame stackFrames;   // stack frames being saved/restored
-
-        private static readonly char[] justacomma = { ',' };
-
-        /*
-         * These arrays hold the global variable values for the script instance.
-         * The array lengths are determined by the script compilation,
-         * and are found in ScriptObjCode.glblSizes.
-         */
-        public XMRInstArrays glblVars;
-
-        public XMRInstAbstract ()
-        {
-            glblVars = new XMRInstArrays (this);
-        }
-
-        /****************************************************************\
-         *  Abstract function prototypes.                               *
-         *  These functions require access to the OpenSim environment.  *
-        \****************************************************************/
-
-        public abstract void CheckRunWork ();
-        public abstract void StateChange  ();
-        public abstract int  xmrStackLeft ();
-
-        [xmrMethodCallsCheckRunAttribute] // calls CheckRun()
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract LSL_List xmrEventDequeue (double timeout, int returnMask1, int returnMask2,
-                                                  int backgroundMask1, int backgroundMask2);
-
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract void xmrEventEnqueue (LSL_List ev);
-
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract LSL_List xmrEventSaveDets ();
-
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract void xmrEventLoadDets (LSL_List dpList);
-
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract void xmrTrapRegionCrossing (int en);
-
-        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
-        public abstract bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int options, int evcode, LSL_List evargs);
-
-        /************************************\
-         *  Constants available to scripts  *
-        \************************************/
-
-        public const int XMRSORPRA_FLYACROSS = 0x00000001;
-
-        /**************************************************\
-         *  Functions what don't require runtime support  *
-         *  beyond what the compiler provides.            *
-        \**************************************************/
-
-        protected int heapLimit;
-        private   int heapUsed;
-
-        public virtual int UpdateHeapUse (int olduse, int newuse)
-        {
-            if (newuse <= olduse) {
-                Interlocked.Add (ref heapUsed, newuse - olduse);
-            } else {
-                int newtotal, oldtotal;
-                do {
-                    oldtotal = Interlocked.Add (ref heapUsed, 0);
-                    newtotal = oldtotal + newuse - olduse;
-                    if (newtotal > heapLimit) {
-                        System.GC.Collect ();
-                        System.GC.WaitForPendingFinalizers ();
-                        oldtotal = Interlocked.Add (ref heapUsed, 0);
-                        newtotal = oldtotal + newuse - olduse;
-                        if (newtotal > heapLimit) {
-                            throw new OutOfHeapException (oldtotal, newtotal, heapLimit);
-                        }
-                    }
-                } while (Interlocked.CompareExchange (ref heapUsed, newtotal, oldtotal) != oldtotal);
-            }
-
-            return newuse;
-        }
-
-        public int xmrHeapLeft ()
-        {
-            return heapLimit - heapUsed;
-        }
-        public int xmrHeapUsed ()
-        {
-            return heapUsed;
-        }
-
-        /**
-         * @brief Call script's event handler function from the very beginning.
-         * @param instance.stateCode = which state the event is happening in
-         * @param instance.eventCode = which event is happening in that state
-         * @returns when event handler has completed or throws an exception
-         *          with instance.eventCode = ScriptEventCode.None
-         */
-        public void CallSEH ()
-        {
-            ScriptEventHandler seh;
-
-            /*
-             * CallMode_NORMAL:  run event handler from the beginning normally
-             * CallMode_RESTORE: restore event handler stack from stackFrames
-             */
-            callMode = (stackFrames == null) ? XMRInstAbstract.CallMode_NORMAL :
-                                               XMRInstAbstract.CallMode_RESTORE;
-
-            while (true)
-            {
-                if (this.newStateCode < 0)
-                {
-                     // Process event given by 'stateCode' and 'eventCode'.
-                     // The event handler should call CheckRun() as often as convenient.
-
-                    int newState = this.stateCode;
-                    seh = this.m_ObjCode.scriptEventHandlerTable[newState,(int)this.eventCode];
-                    if (seh != null)
-                    {
-                        try
-                        {
-                            seh (this);
-                        }
-                        catch (ScriptChangeStateException scse)
-                        {
-                            newState = scse.newState;
-                        }
-                    }
-                    this.ehArgs = null;  // we are done with them and no args for
-                                         // exit_state()/enter_state() anyway
-
-                     // The usual case is no state change.
-                     // Even a 'state <samestate>;' statement has no effect except to exit out.
-                     // It does not execute the state_exit() or state_entry() handlers.
-                     // See http://wiki.secondlife.com/wiki/State
-                    if (newState == this.stateCode)
-                        break;
-
-                     // Save new state in a more permanent location in case we
-                     // get serialized out while in the state_exit() handler.
-                    this.newStateCode = newState;
-                }
-
-                 // Call old state's state_exit() handler.
-                this.eventCode = ScriptEventCode.state_exit;
-                seh = this.m_ObjCode.scriptEventHandlerTable[this.stateCode,(int)ScriptEventCode.state_exit];
-                if (seh != null)
-                {
-                    try
-                    {
-                        seh (this);
-                    }
-                    catch (ScriptChangeStateException scse)
-                    {
-                        this.newStateCode = scse.newState;
-                    }
-                }
-
-                 // Switch over to the new state's state_entry() handler.
-                this.stateCode    = this.newStateCode;
-                this.eventCode    = ScriptEventCode.state_entry;
-                this.newStateCode = -1;
-
-                 // Now that the old state can't possibly start any more activity,
-                 // cancel any listening handlers, etc, of the old state.
-                this.StateChange ();
-
-                 // Loop back to execute new state's state_entry() handler.
-            }
-
-             // Event no longer being processed.
-            this.eventCode = ScriptEventCode.None;
-        }
-
-        /**
-         * @brief For compatibility with old code.
-         */
-        public void CheckRun (int line)
-        {
-            CheckRunStack ();
-        }
-
-        /**
-         * @brief Called at beginning of complex functions to see if they
-         *        are nested too deep possibly in a recursive loop.
-         */
-        public void CheckRunStack ()
-        {
-            if (xmrStackLeft () < stackLimit)
-            {
-                throw new OutOfStackException ();
-            }
-            CheckRunQuick ();
-        }
-
-        /**
-         * @brief Called in each iteration of a loop to see if running too long.
-         */
-        public void CheckRunQuick ()
-        {
-//            if (suspendOnCheckRunHold || suspendOnCheckRunTemp) {
-                CheckRunWork ();
-//            }
-        }
-
-        /**
-         * @brief Called during CallMode_SAVE to create a stackframe save object that saves 
-         *        local variables and calling point within the function.
-         * @param funcName = name of function whose frame is being saved
-         * @param callNo = call number (ie, return address) within function to restart at
-         * @param nSaves = number of variables the function will save
-         * @returns an object[nSaves] where function can save variables
-         */
-        public object[] CaptureStackFrame (string funcName, int callNo, int nSaves)
-        {
-            XMRStackFrame sf = new XMRStackFrame ();
-            sf.nextSF   = stackFrames;
-            sf.funcName = funcName;
-            sf.callNo   = callNo;
-            sf.objArray = new object[nSaves];
-            stackFrames = sf;
-            return sf.objArray;
-        }
-
-        /**
-         * @brief Called during CallMode_RESTORE to pop a stackframe object to restore 
-         *        local variables and calling point within the function.
-         * @param funcName = name of function whose frame is being restored
-         * @returns the object[nSaves] where function can retrieve variables
-         *          callNo = as passed to CaptureStackFrame() indicating restart point
-         */
-        public object[] RestoreStackFrame (string funcName, out int callNo)
-        {
-            XMRStackFrame sf = stackFrames;
-            if (sf.funcName != funcName)
-            {
-                throw new Exception ("frame mismatch " + sf.funcName + " vs " + funcName);
-            }
-            callNo = sf.callNo;
-            stackFrames = sf.nextSF;
-            return sf.objArray;
-        }
-
-        /**
-         * @brief Convert all LSL_Integers in a list to System.Int32s, 
-         *        as required by llParcelMediaQuery().
-         */
-/*
-        public static LSL_List FixLLParcelMediaQuery (LSL_List oldlist)
-        {
-            object[] oldarray = oldlist.Data;
-            int len = oldarray.Length;
-            object[] newarray = new object[len];
-            for (int i = 0; i < len; i ++)
-            {
-                object obj = oldarray[i];
-                if (obj is LSL_Integer) obj = (int)(LSL_Integer)obj;
-                newarray[i] = obj;
-            }
-            return new LSL_List (newarray);
-        }
-*/
-        /**
-         * @brief Convert *SOME* LSL_Integers in a list to System.Int32s, 
-         *        as required by llParcelMediaCommandList().
-         */
-/*
-        public static LSL_List FixLLParcelMediaCommandList (LSL_List oldlist)
-        {
-            object[] oldarray = oldlist.Data;
-            int len = oldarray.Length;
-            object[] newarray = new object[len];
-            int verbatim = 0;
-            for (int i = 0; i < len; i ++)
-            {
-                object obj = oldarray[i];
-                if (-- verbatim < 0)
-                {
-                    if (obj is LSL_Integer)
-                        obj = (int)(LSL_Integer)obj;
-                    if (obj is int)
-                    {
-                        switch ((int)obj)
-                        {
-                            case ScriptBaseClass.PARCEL_MEDIA_COMMAND_AUTO_ALIGN:
-                            {
-                                // leave next integer as LSL_Integer
-                                verbatim = 1;
-                                break;
-                            }
-                            case ScriptBaseClass.PARCEL_MEDIA_COMMAND_SIZE:
-                            {
-                                // leave next two integers as LSL_Integer
-                                verbatim = 2;
-                                break;
-                            }
-                        }
-                    }
-                }
-                newarray[i] = obj;
-            }
-            return new LSL_List (newarray);
-        }
-*/
-        public static int xmrHashCode (int i)
-        {
-            return i.GetHashCode ();
-        }
-        public static int xmrHashCode (double f)
-        {
-            return f.GetHashCode ();
-        }
-        public static int xmrHashCode (object o)
-        {
-            return o.GetHashCode ();
-        }
-        public static int xmrHashCode (string s)
-        {
-            return s.GetHashCode ();
-        }
-
-        public bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int evcode, LSL_List evargs)
-        {
-            return xmrSetObjRegPosRotAsync (pos, rot, 0, evcode, evargs);
-        }
-
-        public string xmrTypeName (object o)
-        {
-            /*
-             * Basic types return constant strings of the script-visible type name.
-             */
-            if (o is XMR_Array)    return "array";
-            if (o is bool)         return "bool";
-            if (o is char)         return "char";
-            if (o is Exception)    return "exception";
-            if (o is double)       return "float";
-            if (o is float)        return "float";
-            if (o is LSL_Float)    return "float";
-            if (o is int)          return "integer";
-            if (o is LSL_Integer)  return "integer";
-            if (o is LSL_List)     return "list";
-            if (o is LSL_Rotation) return "rotation";
-            if (o is LSL_String)   return "string";
-            if (o is string)       return "string";
-            if (o is LSL_Vector)   return "vector";
-
-            /*
-             * A script-defined interface is represented as an array of delegates.
-             * If that is the case, convert it to the object of the script-defined 
-             * class that is implementing the interface.  This should let the next 
-             * step get the script-defined type name of the object.
-             */
-            if (o is Delegate[])
-            {
-                o = ((Delegate[])o)[0].Target;
-            }
-
-            /*
-             * If script-defined class instance, get the script-defined 
-             * type name.
-             */
-            if (o is XMRSDTypeClObj)
-            {
-                return ((XMRSDTypeClObj)o).sdtcClass.longName.val;
-            }
-
-            /*
-             * If it's a delegate, maybe we can look up its script-defined type name.
-             */
-            Type ot = o.GetType ();
-            if (o is Delegate)
-            {
-                String os;
-                if (m_ObjCode.sdDelTypes.TryGetValue (ot, out os)) return os;
-            }
-
-            /*
-             * Don't know what it is, get the C#-level type name.
-             */
-            return ot.ToString ();
-        }
-
-        /**
-         * @brief Call the current state's event handler.
-         * @param ev = as returned by xmrEventDequeue saying which event handler to call
-         *             and what argument list to pass to it.  The llDetect...() parameters
-         *             are as currently set for the script (use xmrEventLoadDets to set how
-         *             you want them to be different).
-         */
-        public void xmrEventCallHandler (LSL_List ev)
-        {
-            object[] data = ev.Data;
-            int evc = (int)(ev.GetLSLIntegerItem (0).value & 0xFFFFFFFF);
-            ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc];
-            if (seh != null)
-            {
-                int nargs = data.Length - 1;
-                object[] args = new object[nargs];
-                Array.Copy (data, 1, args, 0, nargs);
-
-                object[]        saveEHArgs    = this.ehArgs;
-                ScriptEventCode saveEventCode = this.eventCode;
-
-                this.ehArgs    = args;
-                this.eventCode = (ScriptEventCode)evc;
-
-                seh (this);
-
-                this.ehArgs    = saveEHArgs;
-                this.eventCode = saveEventCode;
-            }
-        }
-
-        /**
-         * @brief Sane substring functions.
-         */
-        public string xmrSubstring (string s, int offset)
-        {
-            if (offset >= s.Length)
-                return "";
-            return s.Substring (offset);
-        }
-        // C# style
-        public string xmrSubstring (string s, int offset, int length)
-        {
-            if (length <= 0)
-                return "";
-            if (offset >= s.Length)
-                return "";
-            if (length > s.Length - offset)
-                length = s.Length - offset;
-            return s.Substring (offset, length);
-        }
-        // java style
-        public string xmrJSubstring (string s, int beg, int end)
-        {
-            if (end <= beg)
-                return "";
-            if (beg >= s.Length)
-                return "";
-            if (end >  s.Length)
-                end = s.Length;
-            return s.Substring (beg, end - beg);
-        }
-
-        /**
-         * @brief String begins and ends with test.
-         */
-        public bool xmrStringStartsWith (string s, string t)
-        {
-            return s.StartsWith (t);
-        }
-        public bool xmrStringEndsWith (string s, string t)
-        {
-            return s.EndsWith (t);
-        }
-
-        /**
-         * @brief [Last]IndexOf with starting position (just like C#)
-         */
-        public int xmrStringIndexOf (string haystack, string needle)
-        {
-            return haystack.IndexOf (needle);
-        }
-        public int xmrStringIndexOf (string haystack, string needle, int startat)
-        {
-            return haystack.IndexOf (needle, startat);
-        }
-        public int xmrStringLastIndexOf (string haystack, string needle)
-        {
-            return haystack.LastIndexOf (needle);
-        }
-        public int xmrStringLastIndexOf (string haystack, string needle, int startat)
-        {
-            return haystack.LastIndexOf (needle, startat);
-        }
-
-        /**
-         * @brief These conversions throw exceptions if there is anything stinky...
-         */
-        public double xmrString2Float (string s)
-        {
-            return double.Parse (s, CultureInfo.InvariantCulture);
-        }
-        public int xmrString2Integer (string s)
-        {
-            s = s.Trim ();
-            if (s.StartsWith ("0x") || s.StartsWith ("0X"))
-                return int.Parse (s.Substring (2), NumberStyles.HexNumber);
-
-            return int.Parse (s, CultureInfo.InvariantCulture);
-        }
-        public LSL_Rotation xmrString2Rotation (string s)
-        {
-            s = s.Trim ();
-            if (!s.StartsWith ("<") || !s.EndsWith (">"))
-                throw new FormatException ("doesn't begin with < and end with >");
-
-            s = s.Substring (1, s.Length - 2);
-            string[] splitup = s.Split (justacomma, 5);
-            if (splitup.Length != 4)
-                throw new FormatException ("doesn't have exactly 3 commas");
-
-            double x = double.Parse (splitup[0], CultureInfo.InvariantCulture);
-            double y = double.Parse (splitup[1], CultureInfo.InvariantCulture);
-            double z = double.Parse (splitup[2], CultureInfo.InvariantCulture);
-            double w = double.Parse (splitup[3], CultureInfo.InvariantCulture);
-            return new LSL_Rotation (x, y, z, w);
-        }
-        public LSL_Vector xmrString2Vector (string s)
-        {
-            s = s.Trim ();
-            if (!s.StartsWith ("<") || !s.EndsWith (">"))
-                throw new FormatException ("doesn't begin with < and end with >");
-
-            s = s.Substring (1, s.Length - 2);
-            string[] splitup = s.Split (justacomma, 4);
-            if (splitup.Length != 3)
-                throw new FormatException ("doesn't have exactly 2 commas");
-
-            double x = double.Parse (splitup[0], CultureInfo.InvariantCulture);
-            double y = double.Parse (splitup[1], CultureInfo.InvariantCulture);
-            double z = double.Parse (splitup[2], CultureInfo.InvariantCulture);
-            return new LSL_Vector (x, y, z);
-        }
-
-        /**
-         * @brief Access C#-style formatted numeric conversions.
-         */
-        public string xmrFloat2String (double val, string fmt)
-        {
-            return val.ToString (fmt, CultureInfo.InvariantCulture);
-        }
-        public string xmrInteger2String (int val, string fmt)
-        {
-            return val.ToString (fmt, CultureInfo.InvariantCulture);
-        }
-        public string xmrRotation2String (LSL_Rotation val, string fmt)
-        {
-            return "<" + val.x.ToString (fmt, CultureInfo.InvariantCulture) + "," +
-                         val.y.ToString (fmt, CultureInfo.InvariantCulture) + "," +
-                         val.z.ToString (fmt, CultureInfo.InvariantCulture) + "," +
-                         val.s.ToString (fmt, CultureInfo.InvariantCulture) + ">";
-        }
-        public string xmrVector2String (LSL_Vector val, string fmt)
-        {
-            return "<" + val.x.ToString (fmt, CultureInfo.InvariantCulture) + "," +
-                         val.y.ToString (fmt, CultureInfo.InvariantCulture) + "," +
-                         val.z.ToString (fmt, CultureInfo.InvariantCulture) + ">";
-        }
-
-        /**
-         * @brief Get a delegate for a script-defined function.
-         * @param name = name of the function including arg types, eg,
-         *               "Verify(array,list,string)"
-         * @param sig  = script-defined type name
-         * @param targ = function's 'this' pointer or null if static
-         * @returns delegate for the script-defined function
-         */
-        public Delegate GetScriptMethodDelegate (string name, string sig, object targ)
-        {
-            DynamicMethod dm = m_ObjCode.dynamicMethods[name];
-            TokenDeclSDTypeDelegate dt = (TokenDeclSDTypeDelegate)m_ObjCode.sdObjTypesName[sig];
-            return dm.CreateDelegate (dt.GetSysType (), targ);
-        }
-
-        /**
-         * @brief Try to cast the thrown object to the given script-defined type.
-         * @param thrown = what object was thrown
-         * @param inst = what script instance we are running in
-         * @param sdtypeindex = script-defined type to try to cast it to
-         * @returns null: thrown is not castable to sdtypename
-         *          else: an object casted to sdtypename
-         */
-        public static object XMRSDTypeCatchTryCastToSDType (object thrown, XMRInstAbstract inst, int sdtypeindex)
-        {
-            TokenDeclSDType sdType = inst.m_ObjCode.sdObjTypesIndx[sdtypeindex];
-
-            /*
-             * If it is a script-defined interface object, convert to the original XMRSDTypeClObj.
-             */
-            if (thrown is Delegate[])
-                thrown = ((Delegate[])thrown)[0].Target;
-
-            /*
-             * If it is a script-defined delegate object, make sure it is an instance of the expected type.
-             */
-            if (thrown is Delegate)
-            {
-                Type ot = thrown.GetType ();
-                Type tt = sdType.GetSysType ();
-                return (ot == tt) ? thrown : null;
-            }
-
-            /*
-             * If it is a script-defined class object, make sure it is an instance of the expected class.
-             */
-            if (thrown is XMRSDTypeClObj)
-            {
-
-                /*
-                 * Step from the object's actual class rootward.
-                 * If we find the requested class along the way, the cast is valid.
-                 * If we run off the end of the root, the cast is not valid.
-                 */
-                for (TokenDeclSDTypeClass ac = ((XMRSDTypeClObj)thrown).sdtcClass; ac != null; ac = ac.extends)
-                {
-                    if (ac == sdType)
-                        return thrown;
-                }
-            }
-
-            /*
-             * Don't know what it is, assume it is not what caller wants.
-             */
-            return null;
-        }
-
-        /**
-         * @brief Allocate and access fixed-dimension arrays.
-         */
-        public static object xmrFixedArrayAllocC (int len) { return new   char[len]; }
-        public static object xmrFixedArrayAllocF (int len) { return new double[len]; }
-        public static object xmrFixedArrayAllocI (int len) { return new    int[len]; }
-        public static object xmrFixedArrayAllocO (int len) { return new object[len]; }
-
-        public static char   xmrFixedArrayGetC (object arr, int idx) { return (  (char[])arr)[idx]; }
-        public static double xmrFixedArrayGetF (object arr, int idx) { return ((double[])arr)[idx]; }
-        public static int    xmrFixedArrayGetI (object arr, int idx) { return (   (int[])arr)[idx]; }
-        public static object xmrFixedArrayGetO (object arr, int idx) { return ((object[])arr)[idx]; }
-
-        public static void xmrFixedArraySetC (object arr, int idx, char   val) {   ((char[])arr)[idx] = val; }
-        public static void xmrFixedArraySetF (object arr, int idx, double val) { ((double[])arr)[idx] = val; }
-        public static void xmrFixedArraySetI (object arr, int idx, int    val) {    ((int[])arr)[idx] = val; }
-        public static void xmrFixedArraySetO (object arr, int idx, object val) { ((object[])arr)[idx] = val; }
-
-        /**
-         * @brief Copy from one script-defined array to another.
-         * @param srcobj = source script-defined array class object pointer
-         * @param srcstart = offset in source array to start copying from
-         * @param dstobj = destination script-defined array class object pointer
-         * @param dststart = offset in destination arry to start copying to
-         * @param count = number of elements to copy
-         */
-        public static void xmrArrayCopy (object srcobj, int srcstart, object dstobj, int dststart, int count)
-        {
-            /*
-             * The script writer should only pass us script-defined class objects.
-             * Throw exception otherwise.
-             */
-            XMRSDTypeClObj srcsdt = (XMRSDTypeClObj)srcobj;
-            XMRSDTypeClObj dstsdt = (XMRSDTypeClObj)dstobj;
-
-            /*
-             * Get the script-visible type name of the arrays, brackets and all.
-             */
-            string srctypename = srcsdt.sdtcClass.longName.val;
-            string dsttypename = dstsdt.sdtcClass.longName.val;
-
-            /*
-             * The part before the first '[' of each should match exactly,
-             * meaning the basic data type (eg, float, List<string>) is the same.
-             * And there must be a '[' in each meaning that it is a script-defined array type.
-             */
-            int i = srctypename.IndexOf ('[');
-            int j = dsttypename.IndexOf ('[');
-            if ((i < 0) || (j < 0))
-                throw new InvalidCastException ("non-array passed: " + srctypename + " and/or " + dsttypename);
-            if ((i != j) || !srctypename.StartsWith (dsttypename.Substring (0, j)))
-                throw new ArrayTypeMismatchException (srctypename + " vs " + dsttypename);
-
-
-            /*
-             * The number of brackets must match exactly.
-             * This permits copying from something like a float[,][] to something like a float[][].
-             * But you cannot copy from a float[][] to a float[] or wisa wersa.
-             * Counting either '[' or ']' would work equally well.
-             */
-            int srclen  = srctypename.Length;
-            int dstlen  = dsttypename.Length;
-            int srcjags = 0;
-            int dstjags = 0;
-            while (++ i < srclen)
-                if (srctypename[i] == ']')
-                    srcjags ++;
-            while (++ j < dstlen)
-                if (dsttypename[j] == ']')
-                    dstjags ++;
-            if (dstjags != srcjags)
-                throw new ArrayTypeMismatchException (srctypename + " vs " + dsttypename);
-
-
-            /*
-             * Perform the copy.
-             */
-            Array srcarray = (Array)srcsdt.instVars.iarObjects[0];
-            Array dstarray = (Array)dstsdt.instVars.iarObjects[0];
-            Array.Copy (srcarray, srcstart, dstarray, dststart, count);
-        }
-
-        /**
-         * @brief Copy from an array to a list.
-         * @param srcar = the array to copy from
-         * @param start = where to start in the array
-         * @param count = number of elements
-         * @returns the list
-         */
-        public static LSL_List xmrArray2List (object srcar, int start, int count)
-        {
-            /*
-             * Get the script-visible type of the array.
-             * We only do arrays.
-             */
-            XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
-            TokenDeclSDTypeClass sdtClass = array.sdtcClass;
-            if (sdtClass.arrayOfRank == 0)
-                throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
-
-
-            /*
-             * Validate objects they want to put in the list.
-             * We can't allow anything funky that OpenSim runtime doesn't expect.
-             */
-            Array srcarray = (Array)array.instVars.iarObjects[0];
-            object[] output = new object[count];
-            for (int i = 0; i < count; i ++)
-            {
-                object src = srcarray.GetValue (i + start);
-                if (src == null)
-                    throw new NullReferenceException ("null element " + i);
-                if (src is double)
-                {
-                    output[i] = new LSL_Float ((double)src);
-                    continue;
-                }
-                if (src is int)
-                {
-                    output[i] = new LSL_Integer ((int)src);
-                    continue;
-                }
-                if (src is LSL_Rotation)
-                {
-                    output[i] = src;
-                    continue;
-                }
-                if (src is LSL_Vector)
-                {
-                    output[i] = src;
-                    continue;
-                }
-                if (src is string)
-                {
-                    output[i] = new LSL_String ((string)src);
-                    continue;
-                }
-                throw new InvalidCastException ("invalid element " + i + " type " + src.GetType ().Name);
-            }
-
-            /*
-             * Make a list out of that now immutable array.
-             */
-            return new LSL_List (output);
-        }
-
-        /**
-         * @brief Copy from a list to an array.
-         * @param srclist  = list to copy from
-         * @param srcstart = where to start in the list
-         * @param dstobj   = array to copy to
-         * @param dststart = where to start in the array
-         * @param count    = number of elements
-         */
-        public static void xmrList2Array (LSL_List srclist, int srcstart, object dstobj, int dststart, int count)
-        {
-            /*
-             * Get the script-visible type of the destination.
-             * We only do arrays.
-             */
-            XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
-            TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
-            if (sdtClass.arrayOfType == null)
-                throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
-
-            /*
-             * Copy from the immutable array to the mutable array.
-             * Strip off any LSL wrappers as the script code doesn't expect any.
-             */
-            object[] srcarr = srclist.Data;
-            Array dstarr    = (Array)dstarray.instVars.iarObjects[0];
-
-            for (int i = 0; i < count; i ++)
-            {
-                object obj = srcarr[i+srcstart];
-                if (obj is LSL_Float)   obj = ((LSL_Float)obj).value;
-                else if (obj is LSL_Integer) obj = ((LSL_Integer)obj).value;
-                else if (obj is LSL_String)  obj = ((LSL_String)obj).m_string;
-                dstarr.SetValue (obj, i + dststart);
-            }
-        }
-
-        /**
-         * @brief Copy from an array of characters to a string.
-         * @param srcar = the array to copy from
-         * @param start = where to start in the array
-         * @param count = number of elements
-         * @returns the string
-         */
-        public static string xmrChars2String (object srcar, int start, int count)
-        {
-            /*
-             * Make sure they gave us a script-defined array object.
-             */
-            XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
-            TokenDeclSDTypeClass sdtClass = array.sdtcClass;
-            if (sdtClass.arrayOfRank == 0)
-                throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
-
-            /*
-             * We get a type cast error from mono if they didn't give us a character array.
-             * But if it is ok, create a string from the requested characters.
-             */
-            char[] srcarray = (char[])array.instVars.iarObjects[0];
-            return new string (srcarray, start, count);
-        }
-
-        /**
-         * @brief Copy from a string to a character array.
-         * @param srcstr   = string to copy from
-         * @param srcstart = where to start in the string
-         * @param dstobj   = array to copy to
-         * @param dststart = where to start in the array
-         * @param count    = number of elements
-         */
-        public static void xmrString2Chars (string srcstr, int srcstart, object dstobj, int dststart, int count)
-        {
-            /*
-             * Make sure they gave us a script-defined array object.
-             */
-            XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
-            TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
-            if (sdtClass.arrayOfType == null)
-                throw new InvalidCastException ("only do arrays not " + sdtClass.longName.val);
-
-            /*
-             * We get a type cast error from mono if they didn't give us a character array.
-             * But if it is ok, copy from the string to the character array.
-             */
-            char[] dstarr = (char[])dstarray.instVars.iarObjects[0];
-            for (int i = 0; i < count; i ++)
-                dstarr[i+dststart] = srcstr[i+srcstart];
-        }
-
-        /**
-         * @brief Implement osParseJSON() so we return an array to the script.
-         *        No coherent example of its use in scripts on web found.
-         * see http://www.json.org/ for more details on JSON
-         */
-        private static LSL_List nullList = new LSL_List (new object[0]);
-        public new XMR_Array osParseJSON (string json)
-        {
-            XMR_Array dict = new XMR_Array (this);
-            int idx = ParseJSON (dict, nullList, json, 0);
-            while (idx < json.Length)
-            {
-                if (json[idx] > ' ')
-                    throw new Exception ("left-over json " + json);
-                idx ++;
-            }
-            return dict;
-        }
-
-        private static int ParseJSON (XMR_Array dict, LSL_List keys, string json, int idx)
-        {
-            char c;
-
-            while ((c = json[idx++]) <= ' ') { }
-            switch (c)
-            {
-
-                // '{' <keystring> ':' <value> [ ',' <keystring> ':' <value> ... ] '}'
-                case '{':
-                {
-                    do
-                    {
-                        string key = ParseJSONString (json, ref idx);
-                        while ((c = json[idx++]) <= ' ') { }
-                        if (c != ':')
-                            throw new Exception ("missing : after key");
-                        idx = ParseJSON (dict, ParseJSONKeyAdd (keys, key), json, idx);
-                        while ((c = json[idx++]) <= ' ') { }
-                    } while (c == ',');
-
-                    if (c != '}')
-                        throw new Exception ("missing , or } after value");
-                    break;
-                }
-
-                // '[' <value> [ ',' <value> ... ] ']'
-                case '[':
-                {
-                    int index = 0;
-                    do
-                    {
-                        object key = index ++;
-                        idx = ParseJSON (dict, ParseJSONKeyAdd (keys, key), json, idx);
-                        while ((c = json[idx++]) <= ' ') { }
-                    } while (c == ',');
-
-                    if (c != ']')
-                        throw new Exception ("missing , or ] after value");
-                    break;
-                }
-
-                // '"'<string>'"'
-                case '"':
-                {
-                    -- idx;
-                    string val = ParseJSONString (json, ref idx);
-                    dict.SetByKey (keys, val);
-                    break;
-                }
-
-                // true false null
-                case 't':
-                {
-                    if (json.Substring (idx, 3) != "rue")
-                        throw new Exception ("bad true in json");
-                    idx += 3;
-                    dict.SetByKey (keys, 1);
-                    break;
-                }
-
-                case 'f':
-                {
-                    if (json.Substring (idx, 4) != "alse")
-                        throw new Exception ("bad false in json");
-                    idx += 4;
-                    dict.SetByKey (keys, 0);
-                    break;
-                }
-
-                case 'n':
-                {
-                    if (json.Substring (idx, 3) != "ull")
-                        throw new Exception ("bad null in json");
-                    idx += 3;
-                    dict.SetByKey (keys, null);
-                    break;
-                }
-
-                // otherwise assume it's a number
-                default:
-                {
-                    -- idx;
-                    object val = ParseJSONNumber (json, ref idx);
-                    dict.SetByKey (keys, val);
-                    break;
-                }
-            }
-
-            return idx;
-        }
-
-        // Given the key for a whole array, create a key for a given element of the array
-        private static LSL_List ParseJSONKeyAdd (LSL_List oldkeys, object key)
-        {
-            int oldkeyslen = oldkeys.Length;
-            object[] array = oldkeys.Data;
-            Array.Resize<object> (ref array, oldkeyslen + 1);
-            array[oldkeyslen] = key;
-            return new LSL_List (array);
-        }
-
-        // Parse out a JSON string
-        private static string ParseJSONString (string json, ref int idx)
-        {
-            char c;
-
-            while ((c = json[idx++]) <= ' ') { }
-            if (c != '"') throw new Exception ("bad start of json string");
-
-            StringBuilder sb = new StringBuilder ();
-            while ((c = json[idx++]) != '"')
-            {
-                if (c == '\\')
-                {
-                    c = json[idx++];
-                    switch (c)
-                    {
-                        case 'b':
-                            c = '\b';
-                            break;
-
-                        case 'f':
-                            c = '\f';
-                            break;
-
-                        case 'n':
-                            c = '\n';
-                            break;
-
-                        case 'r':
-                            c = '\r';
-                            break;
-
-                        case 't':
-                            c = '\t';
-                            break;
-
-                        case 'u':
-                            c = (char) Int32.Parse (json.Substring (idx, 4), 
-                                                    System.Globalization.NumberStyles.HexNumber);
-                            idx += 4;
-                            break;
-
-                        default: break;
-                    }
-                }
-                sb.Append (c);
-            }
-            return sb.ToString ();
-        }
-
-        // Parse out a JSON number
-        private static object ParseJSONNumber (string json, ref int idx)
-        {
-            char c;
-
-            while ((c = json[idx++]) <= ' ') { }
-
-            bool expneg = false;
-            bool isneg  = false;
-            int decpt   = -1;
-            int expon   = 0;
-            int ival    = 0;
-            double dval = 0;
-
-            if (c == '-') {
-                isneg = true;
-                c = json[idx++];
-            }
-            if ((c < '0') || (c > '9'))
-                throw new Exception ("bad json number");
-
-            while ((c >= '0') && (c <= '9'))
-            {
-                dval *= 10;
-                ival *= 10;
-                dval += c - '0';
-                ival += c - '0';
-                c = '\0';
-                if (idx < json.Length)
-                    c = json[idx++];
-            }
-            if (c == '.')
-            {
-                decpt = 0;
-                c = '\0';
-                if (idx < json.Length)
-                    c = json[idx++];
-                while ((c >= '0') && (c <= '9')) {
-                    dval *= 10;
-                    dval += c - '0';
-                    decpt ++;
-                    c = '\0';
-                    if (idx < json.Length)
-                        c = json[idx++];
-                }
-            }
-            if ((c == 'e') || (c == 'E'))
-            {
-                if (decpt < 0)
-                    decpt = 0;
-                c = json[idx++];
-                if (c == '-')
-                    expneg = true;
-                if ((c == '-') || (c == '+'))
-                    c = json[idx++];
-                while ((c >= '0') && (c <= '9'))
-                {
-                    expon *= 10;
-                    expon += c - '0';
-                    c = '\0';
-                    if (idx < json.Length)
-                        c = json[idx++];
-                }
-                if (expneg)
-                    expon = -expon;
-            }
-
-            if (c != 0)
-                --idx;
-            if (decpt < 0)
-            {
-                if (isneg)
-                    ival = -ival;
-                return ival;
-            } else {
-                if (isneg)
-                    dval = -dval;
-                dval *= Math.Pow (10, expon - decpt);
-                return dval;
-            }
-        }
-
-        /**
-         * @brief Exception-related runtime calls.
-         */
-        // Return exception message (no type information just the message)
-        public static string xmrExceptionMessage (Exception ex)
-        {
-            return ex.Message;
-        }
-
-        // Return stack trace (no type or message, just stack trace lines: at ... \n)
-        public string xmrExceptionStackTrace (Exception ex)
-        {
-            return XMRExceptionStackString (ex);
-        }
-
-        // Return value thrown by a throw statement
-        public static object xmrExceptionThrownValue (Exception ex)
-        {
-            return ((ScriptThrownException)ex).thrown;
-        }
-
-        // Return exception's short type name, eg, NullReferenceException, ScriptThrownException, etc.
-        public static string xmrExceptionTypeName (Exception ex)
-        {
-            return ex.GetType ().Name;
-        }
-
-        // internal use only: converts any IL addresses in script-defined methods to source location equivalent
-        // at (wrapper dynamic-method) object.__seh_0_30_default_state_entry (OpenSim.Region.ScriptEngine.XMREngine.XMRInstAbstract) <IL 0x00d65, 0x03a53>
-        public string XMRExceptionStackString (Exception ex)
-        {
-            string st = ex.StackTrace;
-            StringBuilder sb = new StringBuilder ();
-            int wrapDynMethObj = 0;
-            int leftOffAt = 0;
-            while ((wrapDynMethObj = st.IndexOf ("(wrapper dynamic-method) System.Object:", ++ wrapDynMethObj)) >= 0) {
-                try {
-                    int begFuncName  = wrapDynMethObj + 39;
-                    int endFuncName  = st.IndexOf (" (", begFuncName);
-                    string funcName  = st.Substring (begFuncName, endFuncName - begFuncName);
-                    KeyValuePair<int, ScriptSrcLoc>[] srcLocs = m_ObjCode.scriptSrcLocss[funcName];
-
-                    int il0xPrefix   = st.IndexOf (" [0x", endFuncName);
-                    int begILHex     = il0xPrefix + 4;
-                    int endILHex     = st.IndexOf (']', begILHex);
-                    string ilHex     = st.Substring (begILHex, endILHex - begILHex);
-                    int offset       = Int32.Parse (ilHex, System.Globalization.NumberStyles.HexNumber);
-
-                    int srcLocIdx;
-                    int srcLocLen    = srcLocs.Length;
-                    for (srcLocIdx = 0; ++ srcLocIdx < srcLocLen;) {
-                        if (offset < srcLocs[srcLocIdx].Key) break;
-                    }
-                    ScriptSrcLoc srcLoc = srcLocs[--srcLocIdx].Value;
-
-                    sb.Append (st.Substring (leftOffAt, wrapDynMethObj - leftOffAt));
-                    sb.Append (st.Substring (begFuncName, endFuncName - begFuncName));
-                    sb.Append (" <");
-                    sb.Append (srcLoc.file);
-                    sb.Append ('(');
-                    sb.Append (srcLoc.line);
-                    sb.Append (',');
-                    sb.Append (srcLoc.posn);
-                    sb.Append (")>");
-
-                    leftOffAt = ++ endILHex;
-                } catch {
-                }
-            }
-            sb.Append (st.Substring (leftOffAt));
-            return sb.ToString ();
-        }
-
-        /**
-         * @brief List fonts available.
-         */
-        public LSL_List xmrFontsAvailable ()
-        {
-            System.Drawing.FontFamily[] families = System.Drawing.FontFamily.Families;
-            object[] output = new object[families.Length];
-            for (int i = 0; i < families.Length; i ++) {
-                output[i] = new LSL_String (families[i].Name);
-            }
-            return new LSL_List (output);
-        }
-
-        /************************\
-         *  Used by decompiler  *
-        \************************/
-
-        public bool xmrRotationToBool (LSL_Rotation x) { return TypeCast.RotationToBool (x); }
-        public bool xmrStringToBool   (string x)       { return TypeCast.StringToBool   (x); }
-        public bool xmrVectorToBool   (LSL_Vector x)   { return TypeCast.VectorToBool   (x); }
-        public bool xmrKeyToBool      (string x)       { return TypeCast.KeyToBool      (x); }
-        public bool xmrListToBool     (LSL_List x)     { return TypeCast.ListToBool     (x); }
-
-        public int xmrStringCompare (string x, string y) { return string.Compare (x, y); }
-
-        /**
-         * @brief types of data we serialize
-         */
-        private enum Ser : byte {
-            NULL,
-            EVENTCODE,
-            LSLFLOAT,
-            LSLINT,
-            LSLKEY,
-            LSLLIST,
-            LSLROT,
-            LSLSTR,
-            LSLVEC,
-            SYSARRAY,
-            SYSDOUB,
-            SYSFLOAT,
-            SYSINT,
-            SYSSTR,
-            XMRARRAY,
-            DUPREF,
-            SYSBOOL,
-            XMRINST,
-            DELEGATE,
-            SDTCLOBJ,
-            SYSCHAR,
-            SYSERIAL,
-            THROWNEX
-        }
-
-        /**
-         * @brief Write state out to a stream.
-         *        Do not change script state.
-         */
-        public void MigrateOut (BinaryWriter mow)
-        {
-            try {
-                this.migrateOutWriter  = mow;
-                this.migrateOutObjects = new Dictionary<object,int> ();
-                this.migrateOutLists   = new Dictionary<object[],ObjLslList> ();
-                this.SendObjValue (this.ehArgs);
-                mow.Write (this.doGblInit);
-                mow.Write (this.stateCode);
-                mow.Write ((int)this.eventCode);
-                this.glblVars.SendArrays (this.SendObjValue);
-                if (this.newStateCode >= 0) {
-                    mow.Write ("**newStateCode**");
-                    mow.Write (this.newStateCode);
-                }
-                for (XMRStackFrame thisSF = this.stackFrames; thisSF != null; thisSF = thisSF.nextSF) {
-                    mow.Write (thisSF.funcName);
-                    mow.Write (thisSF.callNo);
-                    this.SendObjValue (thisSF.objArray);
-                }
-                mow.Write ("");
-            } finally {
-                this.migrateOutWriter  = null;
-                this.migrateOutObjects = null;
-                this.migrateOutLists   = null;
-            }
-        }
-
-        /**
-         * @brief Write an object to the output stream.
-         * @param graph = object to send
-         */
-        private BinaryWriter migrateOutWriter;
-        private Dictionary<object,int> migrateOutObjects;
-        private Dictionary<object[],ObjLslList> migrateOutLists;
-        public void SendObjValue (object graph)
-        {
-            BinaryWriter mow = this.migrateOutWriter;
-
-            /*
-             * Value types (including nulls) are always output directly.
-             */
-            if (graph == null) {
-                mow.Write ((byte)Ser.NULL);
-                return;
-            }
-            if (graph is ScriptEventCode) {
-                mow.Write ((byte)Ser.EVENTCODE);
-                mow.Write ((int)graph);
-                return;
-            }
-            if (graph is LSL_Float) {
-                mow.Write ((byte)Ser.LSLFLOAT);
-                mow.Write ((double)((LSL_Float)graph).value);
-                return;
-            }
-            if (graph is LSL_Integer) {
-                mow.Write ((byte)Ser.LSLINT);
-                mow.Write ((int)((LSL_Integer)graph).value);
-                return;
-            }
-            if (graph is LSL_Key) {
-                mow.Write ((byte)Ser.LSLKEY);
-                LSL_Key key = (LSL_Key)graph;
-                SendObjValue (key.m_string);  // m_string can be null
-                return;
-            }
-            if (graph is LSL_Rotation) {
-                mow.Write ((byte)Ser.LSLROT);
-                mow.Write ((double)((LSL_Rotation)graph).x);
-                mow.Write ((double)((LSL_Rotation)graph).y);
-                mow.Write ((double)((LSL_Rotation)graph).z);
-                mow.Write ((double)((LSL_Rotation)graph).s);
-                return;
-            }
-            if (graph is LSL_String) {
-                mow.Write ((byte)Ser.LSLSTR);
-                LSL_String str = (LSL_String)graph;
-                SendObjValue (str.m_string);  // m_string can be null
-                return;
-            }
-            if (graph is LSL_Vector) {
-                mow.Write ((byte)Ser.LSLVEC);
-                mow.Write ((double)((LSL_Vector)graph).x);
-                mow.Write ((double)((LSL_Vector)graph).y);
-                mow.Write ((double)((LSL_Vector)graph).z);
-                return;
-            }
-            if (graph is bool) {
-                mow.Write ((byte)Ser.SYSBOOL);
-                mow.Write ((bool)graph);
-                return;
-            }
-            if (graph is double) {
-                mow.Write ((byte)Ser.SYSDOUB);
-                mow.Write ((double)graph);
-                return;
-            }
-            if (graph is float) {
-                mow.Write ((byte)Ser.SYSFLOAT);
-                mow.Write ((float)graph);
-                return;
-            }
-            if (graph is int) {
-                mow.Write ((byte)Ser.SYSINT);
-                mow.Write ((int)graph);
-                return;
-            }
-            if (graph is char) {
-                mow.Write ((byte)Ser.SYSCHAR);
-                mow.Write ((char)graph);
-                return;
-            }
-
-            /*
-             * Script instance pointer is always just that.
-             */
-            if (graph == this) {
-                mow.Write ((byte)Ser.XMRINST);
-                return;
-            }
-
-            /*
-             * Convert lists to object type.
-             * This is compatible with old migration data and also
-             * two vars pointing to same list won't duplicate it.
-             */
-            if (graph is LSL_List) {
-                object[] data = ((LSL_List) graph).Data;
-                ObjLslList oll;
-                if (!this.migrateOutLists.TryGetValue (data, out oll)) {
-                    oll = new ObjLslList ();
-                    oll.objarray = data;
-                    this.migrateOutLists[data] = oll;
-                }
-                graph = oll;
-            }
-
-            /*
-             * If this same exact object was already serialized,
-             * just output an index telling the receiver to use
-             * that same old object, rather than creating a whole
-             * new object with the same values.  Also this prevents
-             * self-referencing objects (like arrays) from causing
-             * an infinite loop.
-             */
-            int ident;
-            if (this.migrateOutObjects.TryGetValue (graph, out ident)) {
-                mow.Write ((byte)Ser.DUPREF);
-                mow.Write (ident);
-                return;
-            }
-
-            /*
-             * Object not seen before, save its address with an unique
-             * ident number that the receiver can easily regenerate.
-             */
-            ident = this.migrateOutObjects.Count;
-            this.migrateOutObjects.Add (graph, ident);
-
-            /*
-             * Now output the object's value(s).
-             * If the object self-references, the object is alreay entered
-             * in the dictionary and so the self-reference will just emit
-             * a DUPREF tag instead of trying to output the whole object 
-             * again.
-             */
-            if (graph is ObjLslList) {
-                mow.Write ((byte)Ser.LSLLIST);
-                ObjLslList oll = (ObjLslList) graph;
-                SendObjValue (oll.objarray);
-            } else if (graph is XMR_Array) {
-                mow.Write ((byte)Ser.XMRARRAY);
-                ((XMR_Array)graph).SendArrayObj (this.SendObjValue);
-            } else if (graph is Array) {
-                Array array = (Array)graph;
-                mow.Write ((byte)Ser.SYSARRAY);
-                mow.Write (SysType2String (array.GetType ().GetElementType ()));
-                mow.Write ((int)array.Length);
-                for (int i = 0; i < array.Length; i ++) {
-                    this.SendObjValue (array.GetValue (i));
-                }
-            } else if (graph is string) {
-                mow.Write ((byte)Ser.SYSSTR);
-                mow.Write ((string)graph);
-            } else if (graph is Delegate) {
-                Delegate del = (Delegate)graph;
-                mow.Write ((byte)Ser.DELEGATE);
-                mow.Write (del.Method.Name);
-                Type delType = del.GetType ();
-                foreach (KeyValuePair<string, TokenDeclSDType> kvp in m_ObjCode.sdObjTypesName) {
-                    TokenDeclSDType sdt = kvp.Value;
-                    if (sdt is TokenDeclSDTypeDelegate) {
-                        TokenDeclSDTypeDelegate sdtd = (TokenDeclSDTypeDelegate)sdt;
-                        if (sdtd.GetSysType () == delType) {
-                            mow.Write (kvp.Key);
-                            goto found;
-                        }
-                    }
-                }
-                throw new Exception ("cant find script-defined delegate for " + del.Method.Name + " type " + del.GetType ());
-            found:
-                SendObjValue (del.Target);
-            } else if (graph is XMRSDTypeClObj) {
-                mow.Write ((byte)Ser.SDTCLOBJ);
-                ((XMRSDTypeClObj)graph).Capture (this.SendObjValue);
-            } else if (graph is ScriptThrownException) {
-                MemoryStream memoryStream = new MemoryStream ();
-                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter = 
-                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
-                bformatter.Serialize (memoryStream, graph);
-                byte[] rawBytes = memoryStream.ToArray ();
-                mow.Write ((byte)Ser.THROWNEX);
-                mow.Write ((int)rawBytes.Length);
-                mow.Write (rawBytes);
-                SendObjValue (((ScriptThrownException)graph).thrown);
-            } else {
-                MemoryStream memoryStream = new MemoryStream ();
-                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter = 
-                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
-                bformatter.Serialize (memoryStream, graph);
-                byte[] rawBytes = memoryStream.ToArray ();
-                mow.Write ((byte)Ser.SYSERIAL);
-                mow.Write ((int)rawBytes.Length);
-                mow.Write (rawBytes);
-            }
-        }
-
-        /**
-         * @brief Use short strings for known type names.
-         */
-        private static string SysType2String (Type type)
-        {
-            if (type.IsArray && (type.GetArrayRank () == 1)) {
-                string str = KnownSysType2String (type.GetElementType ());
-                if (str != null) return str + "[]";
-            } else {
-                string str = KnownSysType2String (type);
-                if (str != null) return str;
-            }
-            return type.ToString ();
-        }
-        private static string KnownSysType2String (Type type)
-        {
-            if (type == typeof (bool))           return "bo";
-            if (type == typeof (char))           return "ch";
-            if (type == typeof (Delegate))       return "de";
-            if (type == typeof (double))         return "do";
-            if (type == typeof (float))          return "fl";
-            if (type == typeof (int))            return "in";
-            if (type == typeof (LSL_List))       return "li";
-            if (type == typeof (object))         return "ob";
-            if (type == typeof (LSL_Rotation))   return "ro";
-            if (type == typeof (XMRSDTypeClObj)) return "sc";
-            if (type == typeof (string))         return "st";
-            if (type == typeof (LSL_Vector))     return "ve";
-            if (type == typeof (XMR_Array))      return "xa";
-            return null;
-        }
-        private static Type String2SysType (string str)
-        {
-            if (str.EndsWith ("[]")) {
-                return String2SysType (str.Substring (0, str.Length - 2)).MakeArrayType ();
-            }
-            if (str == "bo") return typeof (bool);
-            if (str == "ch") return typeof (char);
-            if (str == "de") return typeof (Delegate);
-            if (str == "do") return typeof (double);
-            if (str == "fl") return typeof (float);
-            if (str == "in") return typeof (int);
-            if (str == "li") return typeof (LSL_List);
-            if (str == "ob") return typeof (object);
-            if (str == "ro") return typeof (LSL_Rotation);
-            if (str == "sc") return typeof (XMRSDTypeClObj);
-            if (str == "st") return typeof (string);
-            if (str == "ve") return typeof (LSL_Vector);
-            if (str == "xa") return typeof (XMR_Array);
-            return Type.GetType (str, true);
-        }
-
-        /**
-         * @brief Read state in from a stream.
-         */
-        public void MigrateIn (BinaryReader mir)
-        {
-            try {
-                this.migrateInReader  = mir;
-                this.migrateInObjects = new Dictionary<int, object> ();
-                this.ehArgs    = (object[])this.RecvObjValue ();
-                this.doGblInit = mir.ReadBoolean ();
-                this.stateCode = mir.ReadInt32 ();
-                this.eventCode = (ScriptEventCode)mir.ReadInt32 ();
-                this.newStateCode = -1;
-                this.glblVars.RecvArrays (this.RecvObjValue);
-                XMRStackFrame lastSF = null;
-                string funcName;
-                while ((funcName = mir.ReadString ()) != "") {
-                    if (funcName == "**newStateCode**") {
-                        this.newStateCode = mir.ReadInt32 ();
-                        continue;
-                    }
-                    XMRStackFrame thisSF = new XMRStackFrame ();
-                    thisSF.funcName = funcName;
-                    thisSF.callNo   = mir.ReadInt32 ();
-                    thisSF.objArray = (object[])this.RecvObjValue ();
-                    if (lastSF == null) this.stackFrames = thisSF;
-                                   else lastSF.nextSF = thisSF;
-                    lastSF = thisSF;
-                }
-            } finally {
-                this.migrateInReader  = null;
-                this.migrateInObjects = null;
-            }
-        }
-
-        /**
-         * @brief Read a single value from the stream.
-         * @returns value (boxed as needed)
-         */
-        private BinaryReader migrateInReader;
-        private Dictionary<int, object> migrateInObjects;
-        public object RecvObjValue ()
-        {
-            BinaryReader mir = this.migrateInReader;
-            int ident = this.migrateInObjects.Count;
-            Ser code = (Ser)mir.ReadByte ();
-            switch (code) {
-                case Ser.NULL: {
-                    return null;
-                }
-                case Ser.EVENTCODE: {
-                    return (ScriptEventCode)mir.ReadInt32 ();
-                }
-                case Ser.LSLFLOAT: {
-                    return new LSL_Float (mir.ReadDouble ());
-                }
-                case Ser.LSLINT: {
-                    return new LSL_Integer (mir.ReadInt32 ());
-                }
-                case Ser.LSLKEY: {
-                    return new LSL_Key ((string)RecvObjValue ());
-                }
-                case Ser.LSLLIST: {
-                    this.migrateInObjects.Add (ident, null);    // placeholder
-                    object[] data = (object[])RecvObjValue ();  // read data, maybe using another index
-                    LSL_List list = new LSL_List (data);        // make LSL-level list
-                    this.migrateInObjects[ident] = list;        // fill in slot
-                    return list;
-                }
-                case Ser.LSLROT: {
-                    double x = mir.ReadDouble ();
-                    double y = mir.ReadDouble ();
-                    double z = mir.ReadDouble ();
-                    double s = mir.ReadDouble ();
-                    return new LSL_Rotation (x, y, z, s);
-                }
-                case Ser.LSLSTR: {
-                    return new LSL_String ((string)RecvObjValue ());
-                }
-                case Ser.LSLVEC: {
-                    double x = mir.ReadDouble ();
-                    double y = mir.ReadDouble ();
-                    double z = mir.ReadDouble ();
-                    return new LSL_Vector (x, y, z);
-                }
-                case Ser.SYSARRAY: {
-                    Type eletype = String2SysType (mir.ReadString ());
-                    int length = mir.ReadInt32 ();
-                    Array array = Array.CreateInstance (eletype, length);
-                    this.migrateInObjects.Add (ident, array);
-                    for (int i = 0; i < length; i ++) {
-                        array.SetValue (RecvObjValue (), i);
-                    }
-                    return array;
-                }
-                case Ser.SYSBOOL: {
-                    return mir.ReadBoolean ();
-                }
-                case Ser.SYSDOUB: {
-                    return mir.ReadDouble ();
-                }
-                case Ser.SYSFLOAT: {
-                    return mir.ReadSingle ();
-                }
-                case Ser.SYSINT: {
-                    return mir.ReadInt32 ();
-                }
-                case Ser.SYSCHAR: {
-                    return mir.ReadChar ();
-                }
-                case Ser.SYSSTR: {
-                    string s = mir.ReadString ();
-                    this.migrateInObjects.Add (ident, s);
-                    return s;
-                }
-                case Ser.XMRARRAY: {
-                    XMR_Array array = new XMR_Array (this);
-                    this.migrateInObjects.Add (ident, array);
-                    array.RecvArrayObj (this.RecvObjValue);
-                    return array;
-                }
-                case Ser.DUPREF: {
-                    ident = mir.ReadInt32 ();
-                    object obj = this.migrateInObjects[ident];
-                    if (obj is ObjLslList) obj = new LSL_List (((ObjLslList) obj).objarray);
-                    return obj;
-                }
-                case Ser.XMRINST: {
-                    return this;
-                }
-                case Ser.DELEGATE: {
-                    this.migrateInObjects.Add (ident, null);  // placeholder
-                    string name  = mir.ReadString ();         // function name
-                    string sig   = mir.ReadString ();         // delegate type
-                    object targ  = this.RecvObjValue ();      // 'this' object
-                    Delegate del = this.GetScriptMethodDelegate (name, sig, targ);
-                    this.migrateInObjects[ident] = del;       // actual value
-                    return del;
-                }
-                case Ser.SDTCLOBJ: {
-                    XMRSDTypeClObj clobj = new XMRSDTypeClObj ();
-                    this.migrateInObjects.Add (ident, clobj);
-                    clobj.Restore (this, this.RecvObjValue);
-                    return clobj;
-                }
-                case Ser.SYSERIAL: {
-                    int rawLength   = mir.ReadInt32 ();
-                    byte[] rawBytes = mir.ReadBytes (rawLength);
-                    MemoryStream memoryStream = new MemoryStream (rawBytes);
-                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter = 
-                            new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
-                    object graph = bformatter.Deserialize (memoryStream);
-                    this.migrateInObjects.Add (ident, graph);
-                    return graph;
-                }
-                case Ser.THROWNEX: {
-                    int rawLength   = mir.ReadInt32 ();
-                    byte[] rawBytes = mir.ReadBytes (rawLength);
-                    MemoryStream memoryStream = new MemoryStream (rawBytes);
-                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter = 
-                            new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
-                    object graph = bformatter.Deserialize (memoryStream);
-                    this.migrateInObjects.Add (ident, graph);
-                    ((ScriptThrownException)graph).thrown = RecvObjValue ();
-                    return graph;
-                }
-                default: throw new Exception ("bad stream code " + code.ToString ());
-            }
-        }
-
-        // wrapper around list object arrays to make sure they are always object types for migration purposes
-        private class ObjLslList {
-            public object[] objarray;
-        }
-    }
-
-    /**
-     * @brief Common access to script microthread.
-     */
-    public interface IScriptUThread : IDisposable
-    {
-        Exception ResumeEx  ();     // called by macrothread to resume execution at most recent Hiber()
-        Exception StartEx   ();     // called by macrothread to start execution at CallSEH()
-        int       Active    ();     // called by macrothread to query state of microthread
-        int       StackLeft ();     // called by microthread to query amount of remaining stack space
-        void      Hiber     ();     // called by microthread to hibernate
-    }
-
-    // Any xmr...() methods that call CheckRun() must be tagged with this attribute
-    // so the ScriptCodeGen will know the method is non-trivial.
-    public class xmrMethodCallsCheckRunAttribute : Attribute { }
-
-    // Any xmr...() methods in xmrengtest that call Stub<somethingorother>() must be 
-    // tagged with this attribute so the -builtins option will tell the user that 
-    // they are a stub function.
-    public class xmrMethodIsNoisyAttribute : Attribute { }
-
-    // Any script callable methods that really return a key not a string should be
-    // tagged with this attribute so the compiler will know they return type key and
-    // not type string.
-    public class xmrMethodReturnsKeyAttribute : Attribute { }
-
-    [SerializableAttribute]
-    public class OutOfHeapException : Exception {
-        public OutOfHeapException (int oldtotal, int newtotal, int limit)
-                : base ("oldtotal=" + oldtotal + ", newtotal=" + newtotal + ", limit=" + limit)
-        { }
-    }
-
-    [SerializableAttribute]
-    public class OutOfStackException : Exception { }
-}

+ 0 - 76
OpenSim/Region/ScriptEngine/XMREngine/XMRInstSorpra.cs

@@ -1,76 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenMetaverse;
-using OpenSim.Framework;
-using OpenSim.Region.Framework.Scenes;
-using OpenSim.Region.ScriptEngine.Shared;
-using System;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    public partial class XMRInstance
-    {
-        /**
-         * @brief If RegionCrossing trapping is enabled, any attempt to move the object
-         *        outside its current region will cause the event to fire and the object
-         *        will remain in its current region.
-         */
-        public override void xmrTrapRegionCrossing (int en)
-        { }
-
-        /**
-         * @brief Move object to new position and rotation asynchronously.
-         *        Can move object across region boundary.
-         * @param pos     = new position within current region (same coords as llGetPos())
-         * @param rot     = new rotation within current region (same coords as llGetRot())
-         * @param options = not used
-         * @param evcode  = not used
-         * @param evargs  = arguments to pass to event handler
-         * @returns false: completed synchronously, no event will be queued
-         */
-        public const double Sorpra_MIN_CROSS  = 1.0 / 512.0;  // ie, ~2mm
-        public const int    Sorpra_TIMEOUT_MS = 30000;        // ie, 30sec
-        public override bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int options, int evcode, LSL_List evargs)
-        {
-            // do the move
-            SceneObjectGroup sog = m_Part.ParentGroup;
-            sog.UpdateGroupRotationPR (pos, rot);
-
-            // it is always synchronous
-            return false;
-        }
-    }
-}

+ 0 - 5476
OpenSim/Region/ScriptEngine/XMREngine/XMRObjectTokens.cs

@@ -1,5476 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Text;
-
-using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
-using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
-using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
-using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
-using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
-using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
-
-/**
- * Contains classes that disassemble or decompile an xmrobj file.
- * See xmrengcomp.cx utility program.
- */
-
-namespace OpenSim.Region.ScriptEngine.XMREngine {
-
-    /*
-     * Encapsulate object code for a method.
-     */
-    public abstract class ObjectTokens {
-        public ScriptObjCode scriptObjCode;
-
-        public ObjectTokens (ScriptObjCode scriptObjCode)
-        {
-            this.scriptObjCode = scriptObjCode;
-        }
-
-        public abstract void Close ();
-        public abstract void BegMethod (DynamicMethod method);
-        public abstract void EndMethod ();
-        public abstract void DefineLabel (int number, string name);
-        public abstract void DefineLocal (int number, string name, string type, Type syType);
-        public abstract void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames);
-        public abstract void MarkLabel (int offset, int number);
-        public abstract void BegExcBlk (int offset);
-        public abstract void BegCatBlk (int offset, Type excType);
-        public abstract void BegFinBlk (int offset);
-        public abstract void EndExcBlk (int offset);
-        public abstract void EmitNull (int offset, OpCode opCode);
-        public abstract void EmitField (int offset, OpCode opCode, FieldInfo field);
-        public abstract void EmitLocal (int offset, OpCode opCode, int number);
-        public abstract void EmitType (int offset, OpCode opCode, Type type);
-        public abstract void EmitLabel (int offset, OpCode opCode, int number);
-        public abstract void EmitLabels (int offset, OpCode opCode, int[] numbers);
-        public abstract void EmitMethod (int offset, OpCode opCode, MethodInfo method);
-        public abstract void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor);
-        public abstract void EmitDouble (int offset, OpCode opCode, double value);
-        public abstract void EmitFloat (int offset, OpCode opCode, float value);
-        public abstract void EmitInteger (int offset, OpCode opCode, int value);
-        public abstract void EmitString (int offset, OpCode opCode, string value);
-    }
-
-    /******************\
-     *  DISASSEMBLER  *
-    \******************/
-
-    public class OTDisassemble : ObjectTokens {
-        private static readonly int OPCSTRWIDTH = 12;
-
-        private Dictionary<int,string> labelNames;
-        private Dictionary<int,string> localNames;
-        private StringBuilder lbuf = new StringBuilder ();
-        private TextWriter twout;
-
-        public OTDisassemble (ScriptObjCode scriptObjCode, TextWriter twout) : base (scriptObjCode)
-        {
-            this.twout = twout;
-        }
-
-        public override void Close ()
-        {
-            twout.WriteLine ("TheEnd.");
-        }
-
-        /**
-         * About to generate object code for this method.
-         */
-        public override void BegMethod (DynamicMethod method)
-        {
-            labelNames = new Dictionary<int,string> ();
-            localNames = new Dictionary<int,string> ();
-
-            twout.WriteLine ("");
-
-            lbuf.Append (method.ReturnType.Name);
-            lbuf.Append (' ');
-            lbuf.Append (method.Name);
-
-            ParameterInfo[] parms = method.GetParameters ();
-            int nArgs = parms.Length;
-            lbuf.Append (" (");
-            for (int i = 0; i < nArgs; i ++) {
-                if (i > 0) lbuf.Append (", ");
-                lbuf.Append (parms[i].ParameterType.Name);
-            }
-            lbuf.Append (')');
-            FlushLine ();
-
-            lbuf.Append ('{');
-            FlushLine ();
-        }
-
-        /**
-         * Dump out reconstructed source for this method.
-         */
-        public override void EndMethod ()
-        {
-            lbuf.Append ('}');
-            FlushLine ();
-        }
-
-        /**
-         * Add instructions to stream.
-         */
-        public override void DefineLabel (int number, string name)
-        {
-            labelNames[number] = name + "$" + number;
-        }
-
-        public override void DefineLocal (int number, string name, string type, Type syType)
-        {
-            localNames[number] = name + "$" + number;
-
-            lbuf.Append ("          ");
-            lbuf.Append (type.PadRight (OPCSTRWIDTH - 1));
-            lbuf.Append (' ');
-            lbuf.Append (localNames[number]);
-            FlushLine ();
-        }
-
-        public override void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames)
-        { }
-
-        public override void MarkLabel (int offset, int number)
-        {
-            LinePrefix (offset);
-            lbuf.Append (labelNames[number]);
-            lbuf.Append (":");
-            FlushLine ();
-        }
-
-        public override void BegExcBlk (int offset)
-        {
-            LinePrefix (offset);
-            lbuf.Append (" BeginExceptionBlock");
-            FlushLine ();
-        }
-
-        public override void BegCatBlk (int offset, Type excType)
-        {
-            LinePrefix (offset);
-            lbuf.Append (" BeginCatchBlock ");
-            lbuf.Append (excType.Name);
-            FlushLine ();
-        }
-
-        public override void BegFinBlk (int offset)
-        {
-            LinePrefix (offset);
-            lbuf.Append (" BeginFinallyBlock");
-            FlushLine ();
-        }
-
-        public override void EndExcBlk (int offset)
-        {
-            LinePrefix (offset);
-            lbuf.Append (" EndExceptionBlock");
-            FlushLine ();
-        }
-
-        public override void EmitNull (int offset, OpCode opCode)
-        {
-            LinePrefix (offset, opCode);
-            FlushLine ();
-        }
-
-        public override void EmitField (int offset, OpCode opCode, FieldInfo field)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (field.DeclaringType.Name);
-            lbuf.Append (':');
-            lbuf.Append (field.Name);
-            lbuf.Append (" -> ");
-            lbuf.Append (field.FieldType.Name);
-            lbuf.Append ("   (field)");
-            FlushLine ();
-        }
-
-        public override void EmitLocal (int offset, OpCode opCode, int number)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (localNames[number]);
-            lbuf.Append ("   (local)");
-            FlushLine ();
-        }
-
-        public override void EmitType (int offset, OpCode opCode, Type type)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (type.Name);
-            lbuf.Append ("   (type)");
-            FlushLine ();
-        }
-
-        public override void EmitLabel (int offset, OpCode opCode, int number)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (labelNames[number]);
-            lbuf.Append ("   (label)");
-            FlushLine ();
-        }
-
-        public override void EmitLabels (int offset, OpCode opCode, int[] numbers)
-        {
-            LinePrefix (offset, opCode);
-
-            int lineLen = lbuf.Length;
-            int nLabels = numbers.Length;
-            for (int i = 0; i < nLabels; i ++) {
-                if (i > 0) {
-                    lbuf.AppendLine ();
-                    lbuf.Append (",".PadLeft (lineLen));
-                }
-                lbuf.Append (labelNames[numbers[i]]);
-            }
-
-            FlushLine ();
-        }
-
-        public override void EmitMethod (int offset, OpCode opCode, MethodInfo method)
-        {
-            LinePrefix (offset, opCode);
-
-            ParameterInfo[] parms = method.GetParameters ();
-            int nArgs = parms.Length;
-            if (method.DeclaringType != null) {
-                lbuf.Append (method.DeclaringType.Name);
-                lbuf.Append (':');
-            }
-            lbuf.Append (method.Name);
-            lbuf.Append ('(');
-            for (int i = 0; i < nArgs; i ++) {
-                if (i > 0) lbuf.Append (",");
-                lbuf.Append (parms[i].ParameterType.Name);
-            }
-            lbuf.Append (") -> ");
-            lbuf.Append (method.ReturnType.Name);
-
-            FlushLine ();
-        }
-
-        public override void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor)
-        {
-            LinePrefix (offset, opCode);
-
-            ParameterInfo[] parms = ctor.GetParameters ();
-            int nArgs = parms.Length;
-            lbuf.Append (ctor.DeclaringType.Name);
-            lbuf.Append (":(");
-            for (int i = 0; i < nArgs; i ++) {
-                if (i > 0) lbuf.Append (",");
-                lbuf.Append (parms[i].ParameterType.Name);
-            }
-            lbuf.Append (")");
-
-            FlushLine ();
-        }
-
-        public override void EmitDouble (int offset, OpCode opCode, double value)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (value.ToString ());
-            lbuf.Append ("   (double)");
-            FlushLine ();
-        }
-
-        public override void EmitFloat (int offset, OpCode opCode, float value)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (value.ToString ());
-            lbuf.Append ("   (float)");
-            FlushLine ();
-        }
-
-        public override void EmitInteger (int offset, OpCode opCode, int value)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append (value.ToString ());
-            lbuf.Append ("   (int)");
-            FlushLine ();
-        }
-
-        public override void EmitString (int offset, OpCode opCode, string value)
-        {
-            LinePrefix (offset, opCode);
-            lbuf.Append ("\"");
-            lbuf.Append (value);
-            lbuf.Append ("\"   (string)");
-            FlushLine ();
-        }
-
-        /**
-         * Put offset and opcode at beginning of line.
-         */
-        private void LinePrefix (int offset, OpCode opCode)
-        {
-            LinePrefix (offset);
-            lbuf.Append ("  ");
-            lbuf.Append (opCode.ToString ().PadRight (OPCSTRWIDTH - 1));
-            lbuf.Append (' ');
-        }
-
-        private void LinePrefix (int offset)
-        {
-            lbuf.Append ("  ");
-            lbuf.Append (offset.ToString ("X4"));
-            lbuf.Append ("  ");
-        }
-
-        /**
-         * Flush line buffer to output file.
-         */
-        private void FlushLine ()
-        {
-            if (lbuf.Length > 0) {
-                twout.WriteLine (lbuf.ToString ());
-                lbuf.Remove (0, lbuf.Length);
-            }
-        }
-    }
-
-    /****************\
-     *  DECOMPILER  *
-    \****************/
-
-    /**
-     * Note:  The decompiler does not handle any xmroption extensions
-     *        such as &&&, |||, ? operators and switch statements, as
-     *        they do branches with a non-empty stack, which is way
-     *        beyond this code's ability to analyze.
-     */
-
-    public class OTDecompile : ObjectTokens {
-        public const string _mainCallNo      = "__mainCallNo$";
-        public const string _callLabel       = "__call_";
-        public const string _callMode        = "callMode";
-        public const string _checkRunQuick   = "CheckRunQuick";
-        public const string _checkRunStack   = "CheckRunStack";
-        public const string _cmRestore       = "__cmRestore";
-        public const string _doBreak         = "dobreak_";
-        public const string _doCont          = "docont_";
-        public const string _doGblInit       = "doGblInit";
-        public const string _doLoop          = "doloop_";
-        public const string _ehArgs          = "ehArgs";
-        public const string _forBreak        = "forbreak_";
-        public const string _forCont         = "forcont_";
-        public const string _forLoop         = "forloop_";
-        public const string _globalvarinit   = "$globalvarinit()";
-        public const string _heapTrackerPop  = "Pop";
-        public const string _heapTrackerPush = "Push";
-        public const string _ifDone          = "ifdone_";
-        public const string _ifElse          = "ifelse_";
-        public const string _llAbstemp       = "llAbstemp";
-        public const string _retlbl          = "__retlbl";
-        public const string _retval          = "__retval$";
-        public const string _whileBreak      = "whilebreak_";
-        public const string _whileCont       = "whilecont_";
-        public const string _whileLoop       = "whileloop_";
-        public const string _xmrinst         = "__xmrinst";
-        public const string _xmrinstlocal    = "__xmrinst$";
-
-        private const string INDENT = "    ";
-        private const string LABELINDENT = "  ";
-
-        private static Dictionary<string,string> typeTranslator = InitTypeTranslator ();
-        private static Dictionary<string,string> InitTypeTranslator ()
-        {
-            Dictionary<string,string> d = new Dictionary<string,string> ();
-            d["Boolean"]    = "integer";
-            d["bool"]       = "integer";
-            d["Double"]     = "float";
-            d["double"]     = "float";
-            d["Int32"]      = "integer";
-            d["int"]        = "integer";
-            d["htlist"]     = "list";
-            d["htobject"]   = "object";
-            d["htstring"]   = "string";
-            d["lslfloat"]   = "float";
-            d["lslint"]     = "integer";
-            d["lsllist"]    = "list";
-            d["lslrot"]     = "rotation";
-            d["lslstr"]     = "string";
-            d["lslvec"]     = "vector";
-            d["Quaternion"] = "rotation";
-            d["String"]     = "string";
-            d["Vector3"]    = "vector";
-            return d;
-        }
-
-        private Dictionary<int,OTLocal> eharglist;
-        private Dictionary<int,OTLabel> labels;
-        private Dictionary<int,OTLocal> locals;
-        private Dictionary<string,string[]> methargnames;
-        private LinkedList<OTCilInstr> cilinstrs;
-        private OTStmtBlock topBlock;
-        private Stack<OTOpnd> opstack;
-        private Stack<OTStmtBegExcBlk> trystack;
-        private Stack<OTStmtBlock> blockstack;
-
-        private int dupNo;
-        private DynamicMethod method;
-        private string laststate;
-        private TextWriter twout;
-
-        public OTDecompile (ScriptObjCode scriptObjCode, TextWriter twout) : base (scriptObjCode)
-        {
-            this.twout = twout;
-            twout.Write ("xmroption dollarsigns;");
-            methargnames = new Dictionary<string,string[]> ();
-        }
-
-        public override void Close ()
-        {
-            if (laststate != null) {
-                twout.Write ("\n}");
-                laststate = null;
-            }
-            twout.Write ('\n');
-        }
-
-        /**
-         * About to generate object code for this method.
-         */
-        public override void BegMethod (DynamicMethod method)
-        {
-            this.method = method;
-
-            eharglist  = new Dictionary<int,OTLocal> ();
-            labels     = new Dictionary<int,OTLabel> ();
-            locals     = new Dictionary<int,OTLocal> ();
-            cilinstrs  = new LinkedList<OTCilInstr> ();
-            opstack    = new Stack<OTOpnd> ();
-            trystack   = new Stack<OTStmtBegExcBlk> ();
-            blockstack = new Stack<OTStmtBlock> ();
-
-            dupNo = 0;
-        }
-
-        /**
-         * Dump out reconstructed source for this method.
-         */
-        public override void EndMethod ()
-        {
-            /*
-             * Convert CIL code to primitive statements.
-             * There are a bunch of labels and internal code such as call stack save restore.
-             */
-            topBlock = new OTStmtBlock ();
-            blockstack.Push (topBlock);
-            for (LinkedListNode<OTCilInstr> link = cilinstrs.First; link != null; link = link.Next) {
-                link.Value.BuildStatements (this, link);
-            }
-
-            /*
-             * Strip out stuff we don't want, such as references to callMode.
-             * This strips out stack frame capture and restore code.
-             */
-            topBlock.StripStuff (null);
-
-            // including a possible final return statement
-            // - delete if void return value
-            // - delete if returning __retval cuz we converted all __retval assignments to return statements
-            if ((topBlock.blkstmts.Last != null) && (topBlock.blkstmts.Last.Value is OTStmtRet)) {
-                OTStmtRet finalret = (OTStmtRet) topBlock.blkstmts.Last.Value;
-                if ((finalret.value == null) ||
-                        ((finalret.value is OTOpndLocal) &&
-                                ((OTOpndLocal) finalret.value).local.name.StartsWith (_retval))) {
-                    topBlock.blkstmts.RemoveLast ();
-                }
-            }
-
-            /**
-             * At this point, all behind-the-scenes references are removed except
-             * that the do/for/if/while blocks are represented by OTStmtCont-style
-             * if/jumps.  So try to convert them to the higher-level structures.
-             */
-            topBlock.DetectDoForIfWhile (null);
-
-            /*
-             * Final strip to get rid of unneeded @forbreak_<suffix>; labels and the like.
-             */
-            topBlock.StripStuff (null);
-
-            /*
-             * Build reference counts so we don't output unneeded declarations,
-             * especially temps and internal variables.
-             */
-            foreach (OTLocal local in locals.Values) {
-                local.nlclreads  = 0;
-                local.nlclwrites = 0;
-            }
-            topBlock.CountRefs ();
-            for (IEnumerator<int> localenum = locals.Keys.GetEnumerator (); localenum.MoveNext ();) {
-                OTLocal local = locals[localenum.Current];
-                if (((local.nlclreads | local.nlclwrites) == 0) || local.name.StartsWith (_xmrinstlocal)) {
-                    locals.Remove (localenum.Current);
-                    localenum = locals.Keys.GetEnumerator ();
-                }
-            }
-
-            /*
-             * Strip the $n off of local vars that are not ambiguous.
-             * Make sure they don't mask globals and arguments as well.
-             */
-            Dictionary<string,int> namecounts = new Dictionary<string,int> ();
-            foreach (Dictionary<int,string> varnames in scriptObjCode.globalVarNames.Values) {
-                foreach (string varname in varnames.Values) {
-                    int count;
-                    if (!namecounts.TryGetValue (varname, out count)) count = 0;
-                    namecounts[varname] = count + 1;
-                }
-            }
-            if (methargnames.ContainsKey (method.Name)) {
-                foreach (string argname in methargnames[method.Name]) {
-                    int count;
-                    if (!namecounts.TryGetValue (argname, out count)) count = 0;
-                    namecounts[argname] = count + 1;
-                }
-            }
-            foreach (OTLocal local in locals.Values) {
-                int i = local.name.LastIndexOf ('$');
-                string name = local.name.Substring (0, i);
-                int count;
-                if (!namecounts.TryGetValue (name, out count)) count = 0;
-                namecounts[name] = count + 1;
-            }
-            foreach (OTLocal local in locals.Values) {
-                int i = local.name.LastIndexOf ('$');
-                string name = local.name.Substring (0, i);
-                int count = namecounts[name];
-                if (count == 1) local.name = name;
-            }
-
-            /*
-             * Print out result.
-             */
-            if (method.Name == _globalvarinit) {
-                GlobalsDump ();
-            } else {
-                MethodDump ();
-            }
-        }
-
-        /**
-         * Add instructions to stream.
-         */
-        public override void DefineLabel (int number, string name)
-        {
-            labels.Add (number, new OTLabel (number, name));
-        }
-        public override void DefineLocal (int number, string name, string type, Type syType)
-        {
-            locals.Add (number, new OTLocal (number, name, type));
-        }
-        public override void DefineMethod (string methName, Type retType, Type[] argTypes, string[] argNames)
-        {
-            methargnames[methName] = argNames;
-        }
-        public override void MarkLabel (int offset, int number)
-        {
-            OTCilInstr label = labels[number];
-            label.offset = offset;
-            cilinstrs.AddLast (label);
-        }
-        public override void BegExcBlk (int offset)
-        {
-            cilinstrs.AddLast (new OTCilBegExcBlk (offset));
-        }
-        public override void BegCatBlk (int offset, Type excType)
-        {
-            cilinstrs.AddLast (new OTCilBegCatBlk (offset, excType));
-        }
-        public override void BegFinBlk (int offset)
-        {
-            cilinstrs.AddLast (new OTCilBegFinBlk (offset));
-        }
-        public override void EndExcBlk (int offset)
-        {
-            cilinstrs.AddLast (new OTCilEndExcBlk (offset));
-        }
-        public override void EmitNull (int offset, OpCode opCode)
-        {
-            cilinstrs.AddLast (new OTCilNull (offset, opCode));
-        }
-        public override void EmitField (int offset, OpCode opCode, FieldInfo field)
-        {
-            cilinstrs.AddLast (new OTCilField (offset, opCode, field));
-        }
-        public override void EmitLocal (int offset, OpCode opCode, int number)
-        {
-            cilinstrs.AddLast (new OTCilLocal (offset, opCode, locals[number]));
-        }
-        public override void EmitType (int offset, OpCode opCode, Type type)
-        {
-            cilinstrs.AddLast (new OTCilType (offset, opCode, type));
-        }
-        public override void EmitLabel (int offset, OpCode opCode, int number)
-        {
-            cilinstrs.AddLast (new OTCilLabel (offset, opCode, labels[number]));
-        }
-        public override void EmitLabels (int offset, OpCode opCode, int[] numbers)
-        {
-            OTLabel[] labelarray = new OTLabel[numbers.Length];
-            for (int i = 0; i < numbers.Length; i ++) {
-                labelarray[i] = labels[numbers[i]];
-            }
-            cilinstrs.AddLast (new OTCilLabels (offset, opCode, labelarray));
-        }
-        public override void EmitMethod (int offset, OpCode opCode, MethodInfo method)
-        {
-            cilinstrs.AddLast (new OTCilMethod (offset, opCode, method));
-        }
-        public override void EmitCtor (int offset, OpCode opCode, ConstructorInfo ctor)
-        {
-            cilinstrs.AddLast (new OTCilCtor (offset, opCode, ctor));
-        }
-        public override void EmitDouble (int offset, OpCode opCode, double value)
-        {
-            cilinstrs.AddLast (new OTCilDouble (offset, opCode, value));
-        }
-        public override void EmitFloat (int offset, OpCode opCode, float value)
-        {
-            cilinstrs.AddLast (new OTCilFloat (offset, opCode, value));
-        }
-        public override void EmitInteger (int offset, OpCode opCode, int value)
-        {
-            cilinstrs.AddLast (new OTCilInteger (offset, opCode, value));
-        }
-        public override void EmitString (int offset, OpCode opCode, string value)
-        {
-            cilinstrs.AddLast (new OTCilString (offset, opCode, value));
-        }
-
-        /**
-         * Add the given statement to the end of the currently open block.
-         */
-        public void AddLastStmt (OTStmt stmt)
-        {
-            blockstack.Peek ().blkstmts.AddLast (stmt);
-        }
-
-        /**
-         * Generate output for $globalvarinit() function.
-         * Also outputs declarations for global variables.
-         */
-        private void GlobalsDump ()
-        {
-            /*
-             * Scan $globalvarinit().  It should only have global var assignments in it.
-             * Also gather up list of variables it initializes.
-             */
-            bool badinit = false;
-            Dictionary<string,string> inittypes = new Dictionary<string,string> ();
-            foreach (OTStmt stmt in topBlock.blkstmts) {
-                if (!(stmt is OTStmtStore)) {
-                    badinit = true;
-                    break;
-                }
-                OTStmtStore store = (OTStmtStore) stmt;
-                if (!(store.varwr is OTOpndGlobal)) {
-                    badinit = true;
-                    break;
-                }
-                OTOpndGlobal globalop = (OTOpndGlobal) store.varwr;
-                inittypes[globalop.PrintableString] = "";
-            }
-
-            /*
-             * Scan through list of all global variables in the script.
-             * Output declarations for those what don't have any init statement for them.
-             * Save the type for those that do have init statements.
-             */
-            bool first = true;
-            foreach (string iartypename in scriptObjCode.globalVarNames.Keys) {
-                Dictionary<int,string> varnames = scriptObjCode.globalVarNames[iartypename];
-                string typename = iartypename.ToLowerInvariant ();
-                if (typename.StartsWith ("iar")) typename = typename.Substring (3);
-                if (typename.EndsWith ("s")) typename = typename.Substring (0, typename.Length - 1);
-                foreach (string varname in varnames.Values) {
-                    if (!badinit && inittypes.ContainsKey (varname)) {
-                        inittypes[varname] = typename;
-                    } else {
-                        if (first) twout.Write ('\n');
-                        twout.Write ('\n' + typename + ' ' + varname + ';');
-                        first = false;
-                    }
-                }
-            }
-
-            /*
-             * If $globalvarinit() has anything bad in it, output it as a function.
-             * Otherwise, output it as a series of global declarations with init values.
-             */
-            if (badinit) {
-                MethodDump ();
-            } else {
-                foreach (OTStmt stmt in topBlock.blkstmts) {
-                    OTStmtStore store = (OTStmtStore) stmt;
-                    OTOpndGlobal globalop = (OTOpndGlobal) store.varwr;
-                    string name = globalop.PrintableString;
-                    if (first) twout.Write ('\n');
-                    twout.Write ('\n' + inittypes[name] + ' ');
-                    store.PrintStmt (twout, "");
-                    first = false;
-                }
-            }
-        }
-
-        /**
-         * Generate output for other functions.
-         */
-        private void MethodDump ()
-        {
-            string indent;
-
-            /*
-             * Event handlers don't have an argument list as such in the original
-             * code.  Instead they have a series of assignments from ehargs[] to
-             * local variables.  So make those local variables look like they are
-             * an argument list.
-             */
-            int i = method.Name.IndexOf (' ');
-            if (i >= 0) {
-
-                /*
-                 * Maybe we have to output the state name.
-                 */
-                string statename = method.Name.Substring (0, i);
-                string eventname = method.Name.Substring (++ i);
-
-                if (laststate != statename) {
-                    if (laststate != null) twout.Write ("\n}");
-                    if (statename == "default") {
-                        twout.Write ("\n\ndefault {");
-                    } else {
-                        twout.Write ("\n\nstate " + statename + " {");
-                    }
-                    laststate = statename;
-                } else {
-                    twout.Write ('\n');
-                }
-
-                /*
-                 * Output event name and argument list.
-                 * Remove from locals list so they don't print below.
-                 */
-                twout.Write ('\n' + INDENT + eventname + " (");
-                MethodInfo meth = typeof (IEventHandlers).GetMethod (eventname);
-                i = 0;
-                foreach (ParameterInfo pi in meth.GetParameters ()) {
-                    // skip the first param cuz it's the XMRInstance arg
-                    if (i > 0) twout.Write (", ");
-                    OTLocal local;
-                    if (eharglist.TryGetValue (i, out local) && locals.ContainsKey (local.number)) {
-                        twout.Write (local.DumpString ());
-                        locals.Remove (local.number);
-                    } else {
-                        // maybe the assignment was removed
-                        // eg, because the local was write-only (not referenced)
-                        // so substitute in placeholder that won't be referenced
-                        twout.Write (AbbrType (pi.ParameterType) + " arg$" + (i + 1));
-                    }
-                    i ++;
-                }
-                twout.Write (')');
-
-                /*
-                 * Indent method body by 4 spaces.
-                 */
-                indent = INDENT;
-            } else {
-
-                /*
-                 * Maybe need to close out previous state.
-                 */
-                if (laststate != null) {
-                    twout.Write ("\n}");
-                    laststate = null;
-                }
-
-                /*
-                 * Output blank line and return type (if any).
-                 */
-                twout.Write ("\n\n");
-                if (method.ReturnType != typeof (void)) {
-                    twout.Write (AbbrType (method.ReturnType) + ' ');
-                }
-
-                /*
-                 * Output method name and argument list.
-                 */
-                int j = method.Name.IndexOf ('(');
-                if (j < 0) {
-                    twout.Write (method.Name);
-                } else {
-                    twout.Write (method.Name.Substring (0, j) + " (");
-                    bool first = true;
-                    j = 0;
-                    foreach (ParameterInfo pi in method.GetParameters ()) {
-                        if (j > 0) {  // skip the XMRInstance arg$0 parameter
-                            if (!first) twout.Write (", ");
-                            twout.Write (AbbrType (pi.ParameterType) + ' ' + MethArgName (j));
-                            first = false;
-                        }
-                        j ++;
-                    }
-                    twout.Write (')');
-                }
-
-                /*
-                 * Don't indent method body at all.
-                 */
-                indent = "";
-            }
-
-            /*
-             * Output local variable declarations.
-             */
-            twout.Write ('\n' + indent + '{');
-            bool didOne = false;
-            foreach (OTLocal local in locals.Values) {
-                twout.Write ('\n' + indent + INDENT + local.DumpString () + ";  // r:" + local.nlclreads + " w:" + local.nlclwrites);
-                didOne = true;
-            }
-            if (didOne) twout.Write ('\n');
-
-            /*
-             * Output statements.
-             */
-            if (topBlock.blkstmts.Count == 0) {
-                twout.Write (" }");
-            } else {
-                topBlock.PrintBodyAndEnd (twout, indent);
-            }
-        }
-
-        /**
-         * Get abbreviated type string.
-         */
-        public static string AbbrType (Type type)
-        {
-            if (type == null) return "null";
-            return AbbrType (type.Name);
-        }
-        public static string AbbrType (string type)
-        {
-            if (type.StartsWith ("OpenSim.Region.ScriptEngine.XMREngine.")) {
-                type = type.Substring (38);
-                int i = type.IndexOf (',');
-                if (i > 0) type = type.Substring (0, i);
-            }
-            if (typeTranslator.ContainsKey (type)) {
-                type = typeTranslator[type];
-            }
-            return type;
-        }
-
-        /**
-         * Get current method's argument name.
-         */
-        public string MethArgName (int index)
-        {
-            string[] argnames;
-            if (methargnames.TryGetValue (method.Name, out argnames) && (index < argnames.Length)) {
-                return argnames[index];
-            }
-            return "arg$" + index;
-        }
-
-        /**
-         * Strip svperflvovs (float) cast from rotation/vector values.
-         */
-        public static OTOpnd StripFloatCast (OTOpnd op)
-        {
-            if (op is OTOpndCast) {
-                OTOpndCast opcast = (OTOpndCast) op;
-                if ((opcast.type == typeof (double)) && (opcast.value is OTOpndInt)) {
-                    return opcast.value;
-                }
-            }
-            return op;
-        }
-
-        /**
-         * Strip svperflvovs Brtrues so we don't end up with stuff like 'if (!! someint) ...'.
-         */
-        public static OTOpnd StripBrtrue (OTOpnd op)
-        {
-            if (op is OTOpndUnOp) {
-                OTOpndUnOp opunop = (OTOpndUnOp) op;
-                if (opunop.opCode == MyOp.Brtrue) return opunop.value;
-            }
-            return op;
-        }
-
-        /*
-         * Local variable declaration.
-         */
-        private class OTLocal {
-            public int number;
-            public string name;
-            public string type;
-
-            public int nlclreads;
-            public int nlclwrites;
-
-            public OTLocal (int number, string name, string type)
-            {
-                this.number = number;
-                this.name   = name.StartsWith ("tmp$") ? name : name + "$" + number;
-                this.type   = type;
-            }
-
-            public string DumpString ()
-            {
-                return AbbrType (type) + ' ' + name;
-            }
-        }
-
-        /***********************************************\
-         *  Tokens that are one-for-one with CIL code  *
-        \***********************************************/
-
-        /*
-         * Part of instruction stream.
-         */
-        public abstract class OTCilInstr {
-            public int offset;     // cil offset
-
-            public OTCilInstr (int offset)
-            {
-                this.offset = offset;
-            }
-
-            public abstract string DumpString ();
-            public abstract void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link);
-
-            protected void CheckEmptyStack (OTDecompile decompile, string opMnemonic)
-            {
-                if (decompile.opstack.Count > 0) {
-                    Console.Error.WriteLine ("CheckEmptyStack: " + decompile.method.Name + " 0x" + offset.ToString ("X") + ": " +
-                            opMnemonic + " stack depth " + decompile.opstack.Count);
-                }
-            }
-        }
-
-        /*
-         * Label mark point.
-         */
-        private class OTLabel : OTCilInstr {
-            public int number;
-            public string name;
-
-            public int lbljumps;
-
-            public OTLabel (int number, string name) : base (-1)
-            {
-                this.number = number;
-                this.name   = name;
-            }
-
-            public string PrintableName {
-                get {
-                    if (name.StartsWith (_doBreak))    return _doBreak    + "$" + number;
-                    if (name.StartsWith (_doCont))     return _doCont     + "$" + number;
-                    if (name.StartsWith (_forBreak))   return _forBreak   + "$" + number;
-                    if (name.StartsWith (_forCont))    return _forCont    + "$" + number;
-                    if (name.StartsWith (_whileBreak)) return _whileBreak + "$" + number;
-                    if (name.StartsWith (_whileCont))  return _whileCont  + "$" + number;
-                    return name;
-                }
-            }
-
-            public override string DumpString ()
-            {
-                return name + ":";
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                OTStmtLabel.AddLast (decompile, this);
-            }
-        }
-
-        /*
-         * 'try {'
-         */
-        private class OTCilBegExcBlk : OTCilInstr {
-            public LinkedList<OTCilBegCatBlk> catches = new LinkedList<OTCilBegCatBlk> ();
-
-            public OTCilBegExcBlk (int offset) : base (offset)
-            { }
-
-            public override string DumpString ()
-            {
-                return "try {";
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                CheckEmptyStack (decompile, "try");
-
-                // link the try itself onto outer block
-                OTStmtBegExcBlk trystmt = new OTStmtBegExcBlk ();
-                decompile.AddLastStmt (trystmt);
-
-                // subsequent statements go to the try block
-                trystmt.tryblock = new OTStmtBlock ();
-                decompile.trystack.Push (trystmt);
-                decompile.blockstack.Push (trystmt.tryblock);
-            }
-        }
-
-        /*
-         * '} catch (...) {'
-         */
-        private class OTCilBegCatBlk : OTCilInstr {
-            public Type excType;
-
-            public OTCilBegCatBlk (int offset, Type excType) : base (offset)
-            {
-                this.excType = excType;
-            }
-
-            public override string DumpString ()
-            {
-                return "} catch (" + AbbrType (excType) + ") {";
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                CheckEmptyStack (decompile, "catch");
-
-                // link the catch itself onto the try statement
-                OTStmtBegExcBlk trystmt = decompile.trystack.Peek ();
-                OTStmtBegCatBlk catstmt = new OTStmtBegCatBlk (excType);
-                trystmt.catches.AddLast (catstmt);
-
-                // start capturing statements into the catch block
-                catstmt.tryblock   = trystmt;
-                catstmt.catchblock = new OTStmtBlock ();
-                decompile.blockstack.Pop ();
-                decompile.blockstack.Push (catstmt.catchblock);
-
-                // fill the stack slot with something for the exception argument
-                OTOpndDup dup = new OTOpndDup (++ decompile.dupNo);
-                decompile.opstack.Push (dup);
-            }
-        }
-
-        /*
-         * '} finally {'
-         */
-        private class OTCilBegFinBlk : OTCilInstr {
-            public OTCilBegFinBlk (int offset) : base (offset)
-            { }
-
-            public override string DumpString ()
-            {
-                return "} finally {";
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                CheckEmptyStack (decompile, "finally");
-
-                // link the finally itself to the try statement
-                OTStmtBegExcBlk trystmt = decompile.trystack.Peek ();
-                OTStmtBegFinBlk finstmt = new OTStmtBegFinBlk ();
-                trystmt.finblock = finstmt;
-
-                // start capturing statements into the finally block
-                finstmt.tryblock = trystmt;
-                finstmt.finblock = new OTStmtBlock ();
-                decompile.blockstack.Pop ();
-                decompile.blockstack.Push (finstmt.finblock);
-            }
-        }
-
-        /*
-         * '}' end of try
-         */
-        private class OTCilEndExcBlk : OTCilInstr {
-            public OTCilEndExcBlk (int offset) : base (offset)
-            { }
-
-            public override string DumpString ()
-            {
-                return "} // end try";
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                CheckEmptyStack (decompile, "endtry");
-
-                // pop the try/catch/finally blocks from stacks
-                decompile.blockstack.Pop ();
-                decompile.trystack.Pop ();
-
-                // subsequent statements collect following the try
-            }
-        }
-
-        /*
-         * Actual opcodes (instructions).
-         */
-        private class OTCilNull : OTCilInstr {
-            public MyOp opCode;
-
-            public OTCilNull (int offset, OpCode opCode) : base (offset)
-            {
-                this.opCode = MyOp.GetByName (opCode.Name);
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString ();
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "conv.i1":
-                    case "conv.i2":
-                    case "conv.i4":
-                    case "conv.i8": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        decompile.opstack.Push (new OTOpndCast (typeof (int), value));
-                        break;
-                    }
-                    case "conv.r4":
-                    case "conv.r8": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        decompile.opstack.Push (new OTOpndCast (typeof (double), value));
-                        break;
-                    }
-                    case "dup": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        if (!(value is OTOpndDup)) {
-                            OTOpndDup dup = new OTOpndDup (++ decompile.dupNo);
-                            OTStmtStore.AddLast (decompile, dup, value);
-                            value = dup;
-                        }
-                        decompile.opstack.Push (value);
-                        decompile.opstack.Push (value);
-                        break;
-                    }
-                    case "endfinally": break;
-                    case "ldarg.0": { decompile.opstack.Push (new OTOpndArg (0, false, decompile)); break; }
-                    case "ldarg.1": { decompile.opstack.Push (new OTOpndArg (1, false, decompile)); break; }
-                    case "ldarg.2": { decompile.opstack.Push (new OTOpndArg (2, false, decompile)); break; }
-                    case "ldarg.3": { decompile.opstack.Push (new OTOpndArg (3, false, decompile)); break; }
-                    case "ldc.i4.0":  { decompile.opstack.Push (new OTOpndInt  (0)); break; }
-                    case "ldc.i4.1":  { decompile.opstack.Push (new OTOpndInt  (1)); break; }
-                    case "ldc.i4.2":  { decompile.opstack.Push (new OTOpndInt  (2)); break; }
-                    case "ldc.i4.3":  { decompile.opstack.Push (new OTOpndInt  (3)); break; }
-                    case "ldc.i4.4":  { decompile.opstack.Push (new OTOpndInt  (4)); break; }
-                    case "ldc.i4.5":  { decompile.opstack.Push (new OTOpndInt  (5)); break; }
-                    case "ldc.i4.6":  { decompile.opstack.Push (new OTOpndInt  (6)); break; }
-                    case "ldc.i4.7":  { decompile.opstack.Push (new OTOpndInt  (7)); break; }
-                    case "ldc.i4.8":  { decompile.opstack.Push (new OTOpndInt  (8)); break; }
-                    case "ldc.i4.m1": { decompile.opstack.Push (new OTOpndInt (-1)); break; }
-                    case "ldelem.i4":
-                    case "ldelem.r4":
-                    case "ldelem.r8":
-                    case "ldelem.ref": {
-                        OTOpnd index = decompile.opstack.Pop ();
-                        OTOpnd array = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndArrayElem.Make (array, index, false, decompile));
-                        break;
-                    }
-                    case "ldnull": {
-                        decompile.opstack.Push (new OTOpndNull ());
-                        break;
-                    }
-                    case "neg":
-                    case "not": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndUnOp.Make (opCode, value));
-                        break;
-                    }
-                    case "pop": {
-                        OTStmtVoid.AddLast (decompile, decompile.opstack.Pop ());
-                        break;
-                    }
-                    case "ret": {
-                        OTOpnd value = null;
-                        if (decompile.method.ReturnType != typeof (void)) {
-                            value = decompile.opstack.Pop ();
-                        }
-                        CheckEmptyStack (decompile);
-                        decompile.AddLastStmt (new OTStmtRet (value));
-                        break;
-                    }
-                    case "stelem.i4":
-                    case "stelem.r8":
-                    case "stelem.ref": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        OTOpnd index = decompile.opstack.Pop ();
-                        OTOpnd array = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, OTOpndArrayElem.Make (array, index, false, decompile), value);
-                        break;
-                    }
-                    case "throw": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        CheckEmptyStack (decompile);
-                        decompile.AddLastStmt (new OTStmtThrow (value, decompile));
-                        break;
-                    }
-                    case "add":
-                    case "and":
-                    case "ceq":
-                    case "cgt":
-                    case "cgt.un":
-                    case "clt":
-                    case "clt.un":
-                    case "div":
-                    case "div.un":
-                    case "mul":
-                    case "or":
-                    case "rem":
-                    case "rem.un":
-                    case "shl":
-                    case "shr":
-                    case "shr.un":
-                    case "sub":
-                    case "xor": {
-                        OTOpnd rite = decompile.opstack.Pop ();
-                        OTOpnd left = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndBinOp.Make (left, opCode, rite));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-
-            protected void CheckEmptyStack (OTDecompile decompile)
-            {
-                CheckEmptyStack (decompile, opCode.ToString ());
-            }
-        }
-
-        private class OTCilField : OTCilNull {
-            public FieldInfo field;
-
-            public OTCilField (int offset, OpCode opCode, FieldInfo field) : base (offset, opCode)
-            {
-                this.field = field;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + field.Name;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldfld": {
-                        OTOpnd obj = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndField.Make (obj, field));
-                        break;
-                    }
-                    case "ldsfld": {
-                        decompile.opstack.Push (new OTOpndSField (field));
-                        break;
-                    }
-                    case "stfld": {
-                        OTOpnd val = decompile.opstack.Pop ();
-                        OTOpnd obj = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, OTOpndField.Make (obj, field), val);
-                        break;
-                    }
-                    case "stsfld": {
-                        OTOpnd val = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, new OTOpndSField (field), val);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilLocal : OTCilNull {
-            public OTLocal local;
-
-            public OTCilLocal (int offset, OpCode opCode, OTLocal local) : base (offset, opCode)
-            {
-                this.local = local;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + local.name;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldloc": {
-                        decompile.opstack.Push (new OTOpndLocal (local));
-                        break;
-                    }
-                    case "ldloca": {
-                        decompile.opstack.Push (new OTOpndLocalRef (local));
-                        break;
-                    }
-                    case "stloc": {
-                        OTOpnd val = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, new OTOpndLocal (local), val);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilType : OTCilNull {
-            public Type type;
-
-            public OTCilType (int offset, OpCode opCode, Type type) : base (offset, opCode)
-            {
-                this.type = type;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + AbbrType (type);
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "box": {
-                        break;
-                    }
-                    case "castclass":
-                    case "unbox.any": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        decompile.opstack.Push (new OTOpndCast (type, value));
-                        break;
-                    }
-                    case "ldelem": {
-                        OTOpnd index = decompile.opstack.Pop ();
-                        OTOpnd array = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndArrayElem.Make (array, index, false, decompile));
-                        break;
-                    }
-                    case "ldelema": {
-                        OTOpnd index = decompile.opstack.Pop ();
-                        OTOpnd array = decompile.opstack.Pop ();
-                        decompile.opstack.Push (OTOpndArrayElem.Make (array, index, true, decompile));
-                        break;
-                    }
-                    case "newarr": {
-                        OTOpnd index = decompile.opstack.Pop ();
-                        decompile.opstack.Push (new OTOpndNewarr (type, index));
-                        break;
-                    }
-                    case "stelem": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        OTOpnd index = decompile.opstack.Pop ();
-                        OTOpnd array = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, OTOpndArrayElem.Make (array, index, false, decompile), value);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilLabel : OTCilNull {
-            public OTLabel label;
-
-            public OTCilLabel (int offset, OpCode opCode, OTLabel label) : base (offset, opCode)
-            {
-                this.label = label;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + label.name;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-
-                    /*
-                     * We don't handle non-empty stack at branch points.
-                     *
-                     * So handle this case specially:
-                     *
-                     *    dup
-                     *    ldc.i4.0
-                     *    bge.s  llAbstemp  << we are here
-                     *    neg
-                     *  llAbstemp:
-                     *
-                     * becomes:
-                     *
-                     *    call llAbs
-                     */
-                    case "bge.s": {
-                        OTOpnd rite = decompile.opstack.Pop ();  // alleged zero
-                        OTOpnd left = decompile.opstack.Pop ();  // alleged dup
-
-                        if ((label.name == _llAbstemp) && (decompile.opstack.Count > 0)) {
-                            LinkedListNode<OTCilInstr> linkneg = link.Next;
-                            if ((left is OTOpndDup) && (rite is OTOpndInt) &&
-                                    (linkneg != null) && (linkneg.Value is OTCilNull) &&
-                                    (((OTCilNull) linkneg.Value).opCode == MyOp.Neg)) {
-                                OTOpndInt riteint = (OTOpndInt) rite;
-                                LinkedListNode<OTCilInstr> linklbl = linkneg.Next;
-                                if ((riteint.value == 0) && (linklbl != null) && (linklbl.Value is OTLabel) &&
-                                        (((OTLabel) linklbl.Value) == label)) {
-                                    linkneg.List.Remove (linkneg);
-                                    linklbl.List.Remove (linklbl);
-                                    MethodInfo method = typeof (ScriptBaseClass).GetMethod ("llAbs");
-                                    OTOpnd[] args = new OTOpnd[] { new OTOpndNull (), decompile.opstack.Pop () };
-                                    OTOpndCall.AddLast (decompile, method, args);
-                                    break;
-                                }
-                            }
-                        }
-
-                        CheckEmptyStack (decompile);
-                        OTOpnd valu = OTOpndBinOp.Make (left, opCode, rite);
-                        OTStmt jump = OTStmtJump.Make (label);
-                        decompile.AddLastStmt (new OTStmtCond (valu, jump));
-                        break;
-                    }
-
-                    case "beq":
-                    case "bge":
-                    case "bgt":
-                    case "ble":
-                    case "blt":
-                    case "bne.un":
-                    case "beq.s":
-                    case "bgt.s":
-                    case "ble.s":
-                    case "blt.s":
-                    case "bne.un.s": {
-                        OTOpnd rite = decompile.opstack.Pop ();
-                        OTOpnd left = decompile.opstack.Pop ();
-                        CheckEmptyStack (decompile);
-                        OTOpnd valu = OTOpndBinOp.Make (left, opCode, rite);
-                        OTStmt jump = OTStmtJump.Make (label);
-                        decompile.AddLastStmt (new OTStmtCond (valu, jump));
-                        break;
-                    }
-                    case "brfalse":
-                    case "brfalse.s":
-                    case "brtrue":
-                    case "brtrue.s": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        CheckEmptyStack (decompile);
-                        OTOpnd valu = OTOpndUnOp.Make (opCode, value);
-                        OTStmt jump = OTStmtJump.Make (label);
-                        decompile.AddLastStmt (new OTStmtCond (valu, jump));
-                        break;
-                    }
-                    case "br":
-                    case "br.s":
-                    case "leave": {
-                        CheckEmptyStack (decompile);
-                        OTStmt jump = OTStmtJump.Make (label);
-                        decompile.AddLastStmt (jump);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilLabels : OTCilNull {
-            public OTLabel[] labels;
-
-            public OTCilLabels (int offset, OpCode opCode, OTLabel[] labels) : base (offset, opCode)
-            {
-                this.labels = labels;
-            }
-
-            public override string DumpString ()
-            {
-                StringBuilder sb = new StringBuilder ();
-                sb.Append (opCode.ToString ());
-                foreach (OTLabel label in labels) {
-                    sb.Append (' ');
-                    sb.Append (label.name);
-                }
-                return sb.ToString ();
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "switch": {
-                        OTOpnd value = decompile.opstack.Pop ();
-                        CheckEmptyStack (decompile);
-                        decompile.AddLastStmt (new OTStmtSwitch (value, labels));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilMethod : OTCilNull {
-            public MethodInfo method;
-
-            public OTCilMethod (int offset, OpCode opCode, MethodInfo method) : base (offset, opCode)
-            {
-                this.method = method;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + method.Name;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "call":
-                    case "callvirt": {
-                        int nargs = method.GetParameters ().Length;
-                        if (!method.IsStatic) nargs ++;
-                        OTOpnd[] args = new OTOpnd[nargs];
-                        for (int i = nargs; -- i >= 0;) {
-                            args[i] = decompile.opstack.Pop ();
-                        }
-                        OTOpndCall.AddLast (decompile, method, args);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilCtor : OTCilNull {
-            public ConstructorInfo ctor;
-
-            public OTCilCtor (int offset, OpCode opCode, ConstructorInfo ctor) : base (offset, opCode)
-            {
-                this.ctor = ctor;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + AbbrType (ctor.DeclaringType);
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "newobj": {
-                        int nargs = ctor.GetParameters ().Length;
-                        OTOpnd[] args = new OTOpnd[nargs];
-                        for (int i = nargs; -- i >= 0;) {
-                            args[i] = decompile.opstack.Pop ();
-                        }
-                        decompile.opstack.Push (OTOpndNewobj.Make (ctor, args));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilDouble : OTCilNull {
-            public double value;
-
-            public OTCilDouble (int offset, OpCode opCode, double value) : base (offset, opCode)
-            {
-                this.value = value;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + value;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldc.r8": {
-                        decompile.opstack.Push (new OTOpndDouble (value));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilFloat : OTCilNull {
-            public float value;
-
-            public OTCilFloat (int offset, OpCode opCode, float value) : base (offset, opCode)
-            {
-                this.value = value;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + value;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldc.r4": {
-                        decompile.opstack.Push (new OTOpndFloat (value));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilInteger : OTCilNull {
-            public int value;
-
-            public OTCilInteger (int offset, OpCode opCode, int value) : base (offset, opCode)
-            {
-                this.value = value;
-            }
-
-            public override string DumpString ()
-            {
-                return opCode.ToString () + ' ' + value;
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldarg":
-                    case "ldarg.s": {
-                        decompile.opstack.Push (new OTOpndArg (value, false, decompile));
-                        break;
-                    }
-                    case "ldarga":
-                    case "ldarga.s": {
-                        decompile.opstack.Push (new OTOpndArg (value, true, decompile));
-                        break;
-                    }
-                    case "ldc.i4":
-                    case "ldc.i4.s": {
-                        decompile.opstack.Push (new OTOpndInt (value));
-                        break;
-                    }
-                    case "starg": {
-                        OTOpnd val = decompile.opstack.Pop ();
-                        OTStmtStore.AddLast (decompile, new OTOpndArg (value, false, decompile), val);
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        private class OTCilString : OTCilNull {
-            public string value;
-
-            public OTCilString (int offset, OpCode opCode, string value) : base (offset, opCode)
-            {
-                this.value = value;
-            }
-
-            public override string DumpString ()
-            {
-                StringBuilder sb = new StringBuilder ();
-                sb.Append (opCode.ToString ());
-                sb.Append (' ');
-                TokenDeclInline.PrintParamString (sb, value);
-                return sb.ToString ();
-            }
-
-            public override void BuildStatements (OTDecompile decompile, LinkedListNode<OTCilInstr> link)
-            {
-                switch (opCode.ToString ()) {
-                    case "ldstr": {
-                        decompile.opstack.Push (new OTOpndString (value));
-                        break;
-                    }
-                    default: throw new Exception ("unknown opcode " + opCode.ToString ());
-                }
-            }
-        }
-
-        /***************************************\
-         *  Tokens what are on operand stack.  *
-        \***************************************/
-
-        public abstract class OTOpnd {
-
-            /**
-             * See if it possibly has any side effects.
-             */
-            public abstract bool HasSideEffects { get; }
-
-            /**
-             * Increment reference counts.
-             */
-            public virtual void CountRefs (bool writing)
-            { }
-
-            /**
-             * If this operand is a 'by reference' operand,
-             * return the corresponding 'by value' operand.
-             */
-            public virtual OTOpnd GetNonByRefOpnd ()
-            {
-                return this;
-            }
-
-            /**
-             * If this operand is same as oldopnd, replace it with newopnd.
-             *
-             * This default just does a shallow search which is ok if this operand does not have any sub-operands.
-             * But it must be overridden for a deep search if this operand has any sub-operands.
-             */
-            public virtual OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                return this;
-            }
-
-            /**
-             * See if the two operands are the same value.
-             * Note that calls might have side-effects so are never the same.
-             */
-            public abstract bool SameAs (OTOpnd other);
-
-            /**
-             * Get a printable string representation of the operand.
-             */
-            public abstract string PrintableString { get; }
-        }
-
-        /**
-         * Argument variable.
-         */
-        private class OTOpndArg : OTOpnd {
-            public int index;
-            public bool byref;
-
-            private OTDecompile decompile;
-
-            public OTOpndArg (int index, bool byref, OTDecompile decompile)
-            {
-                this.index = index;
-                this.byref = byref;
-                this.decompile = decompile;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override OTOpnd GetNonByRefOpnd ()
-            {
-                if (!byref) return this;
-                return new OTOpndArg (index, false, decompile);
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndArg)) return false;
-                return (((OTOpndArg) other).byref == byref) && (((OTOpndArg) other).index == index);
-            }
-
-            public override string PrintableString {
-                get {
-                    string argname = decompile.MethArgName (index);
-                    return byref ? ("ref " + argname) : argname;
-                }
-            }
-        }
-
-        /**
-         * Element of an array.
-         */
-        private class OTOpndArrayElem : OTOpnd {
-            public bool byref;
-            public OTOpnd array;
-            public OTOpnd index;
-
-            public static OTOpnd Make (OTOpnd array, OTOpnd index, bool byref, OTDecompile decompile)
-            {
-                /*
-                 * arg$0.glblVars.iar<type>[<intconst>] is a reference to a global variable
-                 * likewise so is __xmrinst.glblVars.iar<type>[<intconst>]
-                 */
-                if ((array is OTOpndField) && (index is OTOpndInt)) {
-
-                    /*
-                     * arrayfield = (arg$0.glblVars).iar<type>
-                     * arrayfieldobj = arg$0.glblVars
-                     * iartypename = iar<type>
-                     */
-                    OTOpndField arrayfield = (OTOpndField) array;
-                    OTOpnd arrayfieldobj = arrayfield.obj;
-                    string iartypename = arrayfield.field.Name;
-
-                    /*
-                     * See if they are what they are supposed to be.
-                     */
-                    if ((arrayfieldobj is OTOpndField) && iartypename.StartsWith ("iar")) {
-
-                        /*
-                         * arrayfieldobjfield = arg$0.glblVars
-                         */
-                        OTOpndField arrayfieldobjfield = (OTOpndField) arrayfieldobj;
-
-                        /*
-                         * See if the parts are what they are supposed to be.
-                         */
-                        if (IsArg0OrXMRInst (arrayfieldobjfield.obj) && (arrayfieldobjfield.field.Name == "glblVars")) {
-
-                            /*
-                             * Everything matches up, make a global variable instead of an array reference.
-                             */
-                            return new OTOpndGlobal (iartypename, ((OTOpndInt) index).value, byref, decompile.scriptObjCode);
-                        }
-                    }
-                }
-
-                /*
-                 * Other array reference.
-                 */
-                OTOpndArrayElem it = new OTOpndArrayElem ();
-                it.array = array;
-                it.index = index;
-                it.byref = byref;
-                return it;
-            }
-
-            private OTOpndArrayElem () { }
-
-            public override bool HasSideEffects {
-                get {
-                    return array.HasSideEffects || index.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                array.CountRefs (false);
-                index.CountRefs (false);
-            }
-
-            public override OTOpnd GetNonByRefOpnd ()
-            {
-                if (!byref) return this;
-                OTOpndArrayElem it = new OTOpndArrayElem ();
-                it.array = array;
-                it.index = index;
-                return it;
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                array = array.ReplaceOperand (oldopnd, newopnd, ref rc);
-                index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndArrayElem)) return false;
-                OTOpndArrayElem otherae = (OTOpndArrayElem) other;
-                return array.SameAs (otherae.array) && index.SameAs (otherae.index);
-            }
-
-            public override string PrintableString {
-                get {
-                    return (byref ? "ref " : "") + array.PrintableString + "[" + index.PrintableString + "]";
-                }
-            }
-
-            /**
-             * See if the argument is a reference to arg$0 or __xmrinst
-             */
-            public static bool IsArg0OrXMRInst (OTOpnd obj)
-            {
-                if (obj is OTOpndArg) {
-                    OTOpndArg objarg = (OTOpndArg) obj;
-                    return objarg.index == 0;
-                }
-                if (obj is OTOpndLocal) {
-                    OTOpndLocal objlcl = (OTOpndLocal) obj;
-                    return objlcl.local.name.StartsWith (_xmrinstlocal);
-                }
-                return false;
-            }
-        }
-
-        /**
-         * Binary operator.
-         */
-        private class OTOpndBinOp : OTOpnd {
-            public OTOpnd left;
-            public MyOp opCode;
-            public OTOpnd rite;
-
-            private static Dictionary<string,string> xor1ops = InitXor1Ops ();
-
-            private static Dictionary<string,string> InitXor1Ops ()
-            {
-                Dictionary<string,string> d = new Dictionary<string,string> ();
-                d["ceq"] = "cne";
-                d["cge"] = "clt";
-                d["cgt"] = "cle";
-                d["cle"] = "cgt";
-                d["clt"] = "cge";
-                d["cne"] = "ceq";
-                return d;
-            }
-
-            public static OTOpnd Make (OTOpnd left, MyOp opCode, OTOpnd rite)
-            {
-                // ((x clt y) xor 1)  =>  (x cge y)  etc
-                string xor1op;
-                if ((left is OTOpndBinOp) && xor1ops.TryGetValue (((OTOpndBinOp) left).opCode.name, out xor1op) &&
-                    (opCode == MyOp.Xor) &&
-                    (rite is OTOpndInt) && (((OTOpndInt) rite).value == 1)) {
-                    opCode = MyOp.GetByName (xor1op);
-                }
-
-                // handle strcmp() cases (see OTOpndStrCmp)
-                if (left is OTOpndStrCmp) {
-                    OTOpnd strcmp = ((OTOpndStrCmp) left).MakeBinOp (opCode, rite);
-                    if (strcmp != null) return strcmp;
-                }
-
-                // nothing special, make as is
-                OTOpndBinOp it = new OTOpndBinOp ();
-                it.left   = left;
-                it.opCode = opCode;
-                it.rite   = rite;
-                return it;
-            }
-
-            private OTOpndBinOp () { }
-
-            public override bool HasSideEffects {
-                get {
-                    return left.HasSideEffects || rite.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                left.CountRefs (false);
-                rite.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                left = left.ReplaceOperand (oldopnd, newopnd, ref rc);
-                rite = rite.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndBinOp)) return false;
-                OTOpndBinOp otherbo = (OTOpndBinOp) other;
-                return left.SameAs (otherbo.left) && (opCode.ToString () == otherbo.opCode.ToString ()) && rite.SameAs (otherbo.rite);
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-
-                    bool leftneedsparen = ItNeedsParentheses (left, true);
-                    if (leftneedsparen) sb.Append ('(');
-                    sb.Append (left.PrintableString);
-                    if (leftneedsparen) sb.Append (')');
-
-                    sb.Append (' ');
-                    sb.Append (opCode.source);
-                    sb.Append (' ');
-
-                    bool riteneedsparen = ItNeedsParentheses (rite, false);
-                    if (riteneedsparen) sb.Append ('(');
-                    sb.Append (rite.PrintableString);
-                    if (riteneedsparen) sb.Append (')');
-
-                    return sb.ToString ();
-                }
-            }
-
-            /**
-             * See if source code representation requires parentheses around the given operand.
-             * @param it = the other operand to decide about
-             * @param itleft = true: 'it' is on the left of this operand   (A $ B) # C
-             *                false: 'it' is on the right of this operand  A $ (B # C)
-             */
-            private bool ItNeedsParentheses (OTOpnd it, bool itleft)
-            {
-                if (!(it is OTOpndBinOp)) return false;
-                string itop = ((OTOpndBinOp) it).opCode.source;
-                string myop = opCode.source;
-
-                // find them in table.  higher number is for *, lower is for +.
-                int itpi, mypi;
-                if (!precedence.TryGetValue (itop, out itpi)) return true;
-                if (!precedence.TryGetValue (myop, out mypi)) return true;
-                int itpiabs = Math.Abs (itpi);
-                int mypiabs = Math.Abs (mypi);
-
-                // if its precedence is lower (eg +) than my precedence (eg *), it needs parentheses
-                if (itpiabs < mypiabs) return true;
-
-                // if its precedence is higher (eg *) than my precedence (eg +), it doesn't needs parentheses
-                if (itpiabs > mypiabs) return false;
-
-                // if (A $ B) # C, we can safely go without the parentheses
-                if (itleft) return false;
-
-                //  my   it
-                // A $ (B # C) only works without parentheses for commutative $
-                // A - (B + C) and A - (B - C) require parentheses
-                // A + (B - C) does not
-                return mypi < 0;  // neg: things like -, /, etc require parentheses
-                                  // pos: things like +, *, etc do not need parens
-            }
-
-            // see MMRScriptReduce.PrecedenceInit()
-            private static Dictionary<string,int> precedence = InitPrecedence ();
-            private static Dictionary<string,int> InitPrecedence ()
-            {
-                Dictionary<string,int> d = new Dictionary<string,int> ();
-                d["|"]  =  140;
-                d["^"]  =  160;
-                d["&"]  =  180;
-                d["<<"] = -260;
-                d[">>"] = -260;
-                d["+"]  =  280;
-                d["-"]  = -280;
-                d["*"]  =  320;
-                d["/"]  = -320;
-                d["%"]  = -320;
-                return d;
-            }
-        }
-
-        /**
-         * Call with or without return value.
-         */
-        private class OTOpndCall : OTOpnd {
-            private static Dictionary<string,MethodInfo> mathmeths = InitMathMeths ();
-            private static Dictionary<string,MethodInfo> InitMathMeths ()
-            {
-                Dictionary<string,MethodInfo> d = new Dictionary<string,MethodInfo> ();
-                d["Acos"]  = typeof (ScriptBaseClass).GetMethod ("llAcos");
-                d["Asin"]  = typeof (ScriptBaseClass).GetMethod ("llAsin");
-                d["Atan"]  = typeof (ScriptBaseClass).GetMethod ("llAtan");
-                d["Cos"]   = typeof (ScriptBaseClass).GetMethod ("llCos");
-                d["Abs"]   = typeof (ScriptBaseClass).GetMethod ("llFabs");
-                d["Log"]   = typeof (ScriptBaseClass).GetMethod ("llLog");
-                d["Log10"] = typeof (ScriptBaseClass).GetMethod ("llLog10");
-                d["Round"] = typeof (ScriptBaseClass).GetMethod ("llRound");
-                d["Sin"]   = typeof (ScriptBaseClass).GetMethod ("llSin");
-                d["Sqrt"]  = typeof (ScriptBaseClass).GetMethod ("llSqrt");
-                d["Tan"]   = typeof (ScriptBaseClass).GetMethod ("llTan");
-                return d;
-            }
-
-            public MethodInfo method;
-            public OTOpnd[] args;
-
-            // pushes on stack for return-value functions
-            // pushes to end of instruction stream for return-void functions
-            public static void AddLast (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
-            {
-                int nargs = args.Length;
-
-                // heap tracker push is just the single arg value as far as we're concerned
-                if ((nargs == 1) && (method.Name == _heapTrackerPush) && method.DeclaringType.Name.StartsWith ("HeapTracker")) {
-                    decompile.opstack.Push (args[0]);
-                    return;
-                }
-
-                // heap tracker pop is just a store as far as we're concerned
-                if ((nargs == 2) && (method.Name == _heapTrackerPop) && method.DeclaringType.Name.StartsWith ("HeapTracker")) {
-                    OTStmtStore.AddLast (decompile, args[0], args[1]);
-                    return;
-                }
-
-                // string.Compare() is its own thing cuz it has to decompile many ways
-                if ((nargs == 2) && (method.DeclaringType == typeof (string)) && (method.Name == "Compare")) {
-                    decompile.opstack.Push (new OTOpndStrCmp (args[0], args[1]));
-                    return;
-                }
-
-                // ObjectToString, etc, should appear as casts
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToBool")) {
-                    MethodInfo meth = typeof (XMRInstAbstract).GetMethod ("xmr" + method.Name);
-                    AddLast (decompile, meth, new OTOpnd[] { new OTOpndNull (), args[0] });
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToFloat")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (double), args[0]));
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToInteger")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (int), args[0]));
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToList")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (LSL_List), args[0]));
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToRotation")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (LSL_Rotation), args[0]));
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToString")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (string), args[0]));
-                    return;
-                }
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.EndsWith ("ToVector")) {
-                    decompile.opstack.Push (new OTOpndCast (typeof (LSL_Vector), args[0]));
-                    return;
-                }
-
-                if ((method.DeclaringType == typeof (XMRInstAbstract)) && (method.Name == "xmrHeapLeft")) {
-                    AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llGetFreeMemory"), new OTOpnd[] { new OTOpndNull () });
-                    return;
-                }
-
-                // pop to entry in the list/object/string array
-                if (PopToGlobalArray (decompile, method, args)) return;
-
-                // strip off event handler argument unwrapper calls
-                if ((nargs == 1) && (method.DeclaringType == typeof (TypeCast)) && method.Name.StartsWith ("EHArgUnwrap")) {
-                    decompile.opstack.Push (args[0]);
-                    return;
-                }
-
-                // translate Math method to ll method
-                MethodInfo mathmeth;
-                if ((method.DeclaringType == typeof (Math)) && mathmeths.TryGetValue (method.Name, out mathmeth)) {
-                    AddLast (decompile, mathmeth, new OTOpnd[] { new OTOpndNull (), args[0] });
-                    return;
-                }
-                if ((method.DeclaringType == typeof (Math)) && (method.Name == "Atan2")) {
-                    AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llAtan2"), new OTOpnd[] { new OTOpndNull (), args[0], args[1] });
-                    return;
-                }
-                if ((method.DeclaringType == typeof (Math)) && (method.Name == "Pow")) {
-                    AddLast (decompile, typeof (ScriptBaseClass).GetMethod ("llPow"), new OTOpnd[] { new OTOpndNull (), args[0], args[1] });
-                    return;
-                }
-
-                // string concat should be a bunch of adds
-                if ((method.Name == "Concat") && (method.DeclaringType == typeof (string))) {
-                    int k = args.Length;
-                    while (k > 1) {
-                        int j = 0;
-                        int i;
-                        for (i = 0; i + 2 <= k; i += 2) {
-                            args[j++] = OTOpndBinOp.Make (args[i+0], MyOp.Add, args[i+1]);
-                        }
-                        while (i < k) args[j++] = args[i++];
-                        k = j;
-                    }
-                    if (k > 0) decompile.opstack.Push (args[0]);
-                    return;
-                }
-
-                // bunch of calls for rotation and vector arithmetic
-                if ((method.DeclaringType == typeof (BinOpStr)) && BinOpStrCall (decompile, method, args)) return;
-                if ((method.DeclaringType == typeof (ScriptCodeGen)) && (method.Name == "LSLRotationNegate")) {
-                    decompile.opstack.Push (OTOpndUnOp.Make (MyOp.Neg, args[0]));
-                    return;
-                }
-                if ((method.DeclaringType == typeof (ScriptCodeGen)) && (method.Name == "LSLVectorNegate")) {
-                    decompile.opstack.Push (OTOpndUnOp.Make (MyOp.Neg, args[0]));
-                    return;
-                }
-
-                // otherwise process it as a call
-                OTOpndCall call = new OTOpndCall ();
-                call.method = method;
-                call.args   = args;
-                if (method.ReturnType == typeof (void)) {
-                    OTStmtVoid.AddLast (decompile, call);
-                } else {
-                    decompile.opstack.Push (call);
-                }
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return true;
-                }
-            }
-
-            /**
-             * Handle a call to XMRInstArrays.Pop<List,Object,String>
-             * by converting it to a store directly into the array.
-             */
-            private static bool PopToGlobalArray (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
-            {
-                if (method.DeclaringType != typeof (XMRInstArrays)) return false;
-                if (args.Length != 3) return false;
-
-                string array = null;
-                if (method.Name == "PopList")   array = "iarLists";
-                if (method.Name == "PopObject") array = "iarObjects";
-                if (method.Name == "PopString") array = "iarStrings";
-                if (array == null) return false;
-
-                // make token that points to the iar<whatever> array
-                FieldInfo field = typeof (XMRInstArrays).GetField (array);
-                OTOpnd arrayfield = OTOpndField.Make (args[0], field);
-
-                // make token that points to the element to be popped to
-                OTOpnd element = OTOpndArrayElem.Make (arrayfield, args[1], false, decompile);
-
-                // make a statement to store value in that element
-                OTStmtStore.AddLast (decompile, element, args[2]);
-
-                return true;
-            }
-
-            /**
-             * BinOpStr has a bunch of calls to do funky arithmetic.
-             * Instead of generating a call, put back the original source.
-             */
-            private static bool BinOpStrCall (OTDecompile decompile, MethodInfo method, OTOpnd[] args)
-            {
-                switch (method.Name) {
-                    case "MethFloatAddList":
-                    case "MethIntAddList":
-                    case "MethKeyAddList":
-                    case "MethListAddFloat":
-                    case "MethListAddInt":
-                    case "MethListAddKey":
-                    case "MethListAddList":
-                    case "MethListAddObj":
-                    case "MethListAddRot":
-                    case "MethListAddStr":
-                    case "MethListAddVec":
-                    case "MethObjAddList":
-                    case "MethRotAddList":
-                    case "MethRotAddRot":
-                    case "MethStrAddList":
-                    case "MethVecAddList":
-                    case "MethVecAddVec": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Add, args[1]));
-                        return true;
-                    }
-
-                    case "MethListEqList":
-                    case "MethRotEqRot":
-                    case "MethVecEqVec": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Ceq, args[1]));
-                        return true;
-                    }
-
-                    case "MethListNeList":
-                    case "MethRotNeRot":
-                    case "MethVecNeVec": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Cne, args[1]));
-                        return true;
-                    }
-
-                    case "MethRotSubRot":
-                    case "MethVecSubVec": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Sub, args[1]));
-                        return true;
-                    }
-
-                    case "MethFloatMulVec":
-                    case "MethIntMulVec":
-                    case "MethRotMulRot":
-                    case "MethVecMulFloat":
-                    case "MethVecMulInt":
-                    case "MethVecMulRot":
-                    case "MethVecMulVec": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Mul, args[1]));
-                        return true;
-                    }
-
-                    case "MethRotDivRot":
-                    case "MethVecDivFloat":
-                    case "MethVecDivInt":
-                    case "MethVecDivRot": {
-                        decompile.opstack.Push (OTOpndBinOp.Make (args[0], MyOp.Div, args[1]));
-                        return true;
-                    }
-
-                    default: return false;
-                }
-            }
-
-            private OTOpndCall () { }
-
-            public override void CountRefs (bool writing)
-            {
-                foreach (OTOpnd arg in args) {
-                    arg.CountRefs (false);
-                }
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                for (int i = 0; i < args.Length; i ++) {
-                    args[i] = args[i].ReplaceOperand (oldopnd, newopnd, ref rc);
-                }
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                return false;
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-
-                    // GetByKey(a,i) => a[i]
-                    if ((method.DeclaringType == typeof (XMR_Array)) && (method.Name == "GetByKey") && (args.Length == 2)) {
-                        sb.Append (args[0].PrintableString);
-                        sb.Append ('[');
-                        sb.Append (args[1].PrintableString);
-                        sb.Append (']');
-                        return sb.ToString ();
-                    }
-
-                    // SetByKey(a,i,v) => a[i] = v
-                    if ((method.DeclaringType == typeof (XMR_Array)) && (method.Name == "SetByKey") && (args.Length == 3)) {
-                        sb.Append (args[0].PrintableString);
-                        sb.Append ('[');
-                        sb.Append (args[1].PrintableString);
-                        sb.Append ("] = ");
-                        sb.Append (args[2].PrintableString);
-                        return sb.ToString ();
-                    }
-
-                    // CompValuListEl.GetElementFromList accesses list elements like an array.
-                    if ((method.DeclaringType == typeof (CompValuListEl)) && (method.Name == "GetElementFromList")) {
-                        sb.Append (args[0].PrintableString);
-                        sb.Append ('[');
-                        sb.Append (args[1].PrintableString);
-                        sb.Append (']');
-                        return sb.ToString ();
-                    }
-
-                    // methods that are part of ScriptBaseClass are LSL functions such as llSay()
-                    // so we want to skip outputting "arg$0," as it is the hidden "this" argument.
-                    // and there are also XMRInstAbstract functions such as xmrEventDequeue().
-                    int starti = 0;
-                    if ((method.DeclaringType == typeof (ScriptBaseClass)) && !method.IsStatic) starti = 1;
-                    if ((method.DeclaringType == typeof (XMRInstAbstract)) && !method.IsStatic) starti = 1;
-
-                    // likewise, method that have null as the declaring type are script-defined
-                    // dynamic methods which have a hidden "this" argument passed as "arg$0".
-                    if (method.DeclaringType == null) starti = 1;
-
-                    // all others we want to show the type name (such as Math.Abs, String.Compare, etc)
-                    if (starti == 0) {
-                        sb.Append (AbbrType (method.DeclaringType));
-                        sb.Append ('.');
-                    }
-
-                    // script-defined functions have the param types as part of their name
-                    // so strip them off here so they don't clutter things up
-                    int i = method.Name.IndexOf ('(');
-                    if (i < 0) sb.Append (method.Name);
-                    else sb.Append (method.Name.Substring (0, i));
-
-                    // now add the call arguments
-                    sb.Append (" (");
-                    bool first = true;
-                    foreach (OTOpnd arg in args) {
-                        if (-- starti < 0) {
-                            if (!first) sb.Append (", ");
-                            sb.Append (arg.PrintableString);
-                            first = false;
-                        }
-                    }
-                    sb.Append (')');
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Cast value to the given type.
-         */
-        private class OTOpndCast : OTOpnd {
-            public Type type;
-            public OTOpnd value;
-
-            public OTOpndCast (Type type, OTOpnd value)
-            {
-                this.type  = type;
-                this.value = value;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return value.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                value.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndCast)) return false;
-                OTOpndCast othercast = (OTOpndCast) other;
-                return (type == othercast.type) && value.SameAs (othercast.value);
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    sb.Append ('(');
-                    sb.Append (AbbrType (type));
-                    sb.Append (") ");
-                    if (value is OTOpndBinOp) sb.Append ('(');
-                    sb.Append (value.PrintableString);
-                    if (value is OTOpndBinOp) sb.Append (')');
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Duplicate stack value without re-performing computation.
-         * Semantics just like local var except it doesn't have a declaration.
-         */
-        private class OTOpndDup : OTOpnd {
-            public int index;
-            public int ndupreads;
-
-            public OTOpndDup (int index)
-            {
-                this.index = index;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                if (!writing) ndupreads ++;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndDup)) return false;
-                return ((OTOpndDup) other).index == index;
-            }
-
-            public override string PrintableString { get { return "dup$" + index; } }
-        }
-
-        /**
-         * Field of an object.
-         */
-        private class OTOpndField : OTOpnd {
-            public OTOpnd obj;
-            public FieldInfo field;
-
-            public static OTOpnd Make (OTOpnd obj, FieldInfo field)
-            {
-                //  LSL_Float.value => the object itself
-                if ((field.DeclaringType == typeof (LSL_Float)) && (field.Name == "value")) {
-                    return obj;
-                }
-
-                //  LSL_Integer.value => the object itself
-                if ((field.DeclaringType == typeof (LSL_Integer)) && (field.Name == "value")) {
-                    return obj;
-                }
-
-                // LSL_String.m_string => the object itself
-                if ((field.DeclaringType == typeof (LSL_String)) && (field.Name == "m_string")) {
-                    return obj;
-                }
-
-                // some other field, output code to access it
-                // sometimes the object comes as by reference (value types), so we might need to deref it first
-                OTOpndField it = new OTOpndField ();
-                it.obj   = obj.GetNonByRefOpnd ();
-                it.field = field;
-                return it;
-            }
-
-            private OTOpndField () { }
-
-            public override bool HasSideEffects {
-                get {
-                    return obj.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                // the field may be getting written to, but the object is being read
-                obj.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                obj = obj.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndField)) return false;
-                OTOpndField otherfield = (OTOpndField) other;
-                return (field.Name == otherfield.field.Name) && obj.SameAs (otherfield.obj);
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    if (obj is OTOpndBinOp) sb.Append ('(');
-                    sb.Append (obj.PrintableString);
-                    if (obj is OTOpndBinOp) sb.Append (')');
-                    sb.Append ('.');
-                    sb.Append (field.Name);
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Script-level global variable.
-         */
-        private class OTOpndGlobal : OTOpnd {
-            public string iartypename;
-            public int iararrayidx;
-            public bool byref;
-            public ScriptObjCode scriptObjCode;
-
-            public OTOpndGlobal (string iartypename, int iararrayidx, bool byref, ScriptObjCode scriptObjCode)
-            {
-                this.iartypename   = iartypename;
-                this.iararrayidx   = iararrayidx;
-                this.byref         = byref;
-                this.scriptObjCode = scriptObjCode;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override OTOpnd GetNonByRefOpnd ()
-            {
-                if (!byref) return this;
-                return new OTOpndGlobal (iartypename, iararrayidx, false, scriptObjCode);
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndGlobal)) return false;
-                OTOpndGlobal otherglobal = (OTOpndGlobal) other;
-                return (iartypename == otherglobal.iartypename) && (iararrayidx == otherglobal.iararrayidx);
-            }
-
-            public override string PrintableString {
-                get {
-                    return (byref ? "ref " : "") + scriptObjCode.globalVarNames[iartypename][iararrayidx];
-                }
-            }
-        }
-
-        /**
-         * List initialization.
-         */
-        private class OTOpndListIni : OTOpnd {
-            public OTOpnd[] values;
-
-            /**
-             * Try to detect list initialization building idiom:
-             *    dup$<n> = newarr object[<m>]      << link points here
-             *    dup$<n>[0] = bla
-             *    dup$<n>[1] = bla
-             *        ...
-             *    ... newobj list (dup$<n>) ...
-             */
-            public static bool Detect (LinkedListNode<OTStmt> link)
-            {
-                if (link == null) return false;
-
-                /*
-                 * Check for 'dup$<n> = newarr object[<m>]' and get listsize from <m>.
-                 */
-                OTStmtStore store = (OTStmtStore) link.Value;
-                if (!(store.varwr is OTOpndDup)) return false;
-                if (!(store.value is OTOpndNewarr)) return false;
-                OTOpndDup    storevar = (OTOpndDup) store.varwr;
-                OTOpndNewarr storeval = (OTOpndNewarr) store.value;
-                if (storeval.type != typeof (object)) return false;
-                if (!(storeval.index is OTOpndInt)) return false;
-                int listsize = ((OTOpndInt) storeval.index).value;
-
-                /*
-                 * Good chance of having list initializer, malloc an object to hold it.
-                 */
-                OTOpndListIni it = new OTOpndListIni ();
-                it.values = new OTOpnd[listsize];
-
-                /*
-                 * There should be exactly listsize statements following that of the form:
-                 *    dup$<n>[<i>] = bla
-                 * If so, save the bla values in the values[] array.
-                 */
-                LinkedListNode<OTStmt> vallink = link;
-                for (int i = 0; i < listsize; i ++) {
-                    vallink = vallink.Next;
-                    if (vallink == null) return false;
-                    if (!(vallink.Value is OTStmtStore)) return false;
-                    OTStmtStore valstore = (OTStmtStore) vallink.Value;
-                    if (!(valstore.varwr is OTOpndArrayElem)) return false;
-                    OTOpndArrayElem varelem = (OTOpndArrayElem) valstore.varwr;
-                    if (varelem.array != storevar) return false;
-                    if (!(varelem.index is OTOpndInt)) return false;
-                    if (((OTOpndInt) varelem.index).value != i) return false;
-                    it.values[i] = valstore.value;
-                }
-
-                /*
-                 * The next statement should have a 'newobj list (dup$<n>)' in it somewhere
-                 * that we want to replace with 'it'.
-                 */
-                ConstructorInfo protoctor = typeof (LSL_List).GetConstructor (new Type[] { typeof (object[]) });
-                OTOpnd[] protoargs = new OTOpnd[] { storevar };
-                OTOpnd proto = OTOpndNewobj.Make (protoctor, protoargs);
-
-                vallink = vallink.Next;
-                bool rc = vallink.Value.ReplaceOperand (proto, it);
-
-                /*
-                 * If successful, delete 'dup$n =' and all 'dup$n[i] =' statements.
-                 */
-                if (rc) {
-                    do {
-                        LinkedListNode<OTStmt> nextlink = link.Next;
-                        link.List.Remove (link);
-                        link = nextlink;
-                    } while (link != vallink);
-                }
-
-                return rc;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    foreach (OTOpnd value in values) {
-                        if (value.HasSideEffects) return true;
-                    }
-                    return false;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                foreach (OTOpnd value in values) {
-                    value.CountRefs (false);
-                }
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                for (int i = 0; i < values.Length; i ++) {
-                    values[i] = values[i].ReplaceOperand (oldopnd, newopnd, ref rc);
-                }
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndListIni)) return false;
-                OTOpndListIni otherli = (OTOpndListIni) other;
-                if (otherli.values.Length != values.Length) return false;
-                for (int i = 0; i < values.Length; i ++) {
-                    if (!values[i].SameAs (otherli.values[i])) return false;
-                }
-                return true;
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    sb.Append ('[');
-                    for (int i = 0; i < values.Length; i ++) {
-                        if (i > 0) sb.Append (',');
-                        sb.Append (' ');
-                        sb.Append (values[i].PrintableString);
-                    }
-                    sb.Append (" ]");
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Local variable.
-         */
-        private class OTOpndLocal : OTOpnd {
-            public OTLocal local;
-
-            public OTOpndLocal (OTLocal local)
-            {
-                this.local = local;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                if (writing) local.nlclwrites ++;
-                        else local.nlclreads ++;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndLocal)) return false;
-                OTOpndLocal otherlocal = (OTOpndLocal) other;
-                return local == otherlocal.local;
-            }
-
-            public override string PrintableString {
-                get {
-                    return local.name;
-                }
-            }
-        }
-        private class OTOpndLocalRef : OTOpnd {
-            public OTLocal local;
-
-            public OTOpndLocalRef (OTLocal local)
-            {
-                this.local = local;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return true;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                local.nlclreads  ++;
-                local.nlclwrites ++;
-            }
-
-            public override OTOpnd GetNonByRefOpnd ()
-            {
-                return new OTOpndLocal (local);
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndLocal)) return false;
-                OTOpndLocal otherlocal = (OTOpndLocal) other;
-                return local == otherlocal.local;
-            }
-
-            public override string PrintableString { get { return "ref " + local.name; } }
-        }
-
-        /**
-         * New C#-level array.
-         */
-        private class OTOpndNewarr : OTOpnd {
-            public Type type;
-            public OTOpnd index;
-
-            public OTOpndNewarr (Type type, OTOpnd index)
-            {
-                this.type  = type;
-                this.index = index;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return index.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                index.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                return false;
-            }
-
-            public override string PrintableString { get { return "newarr " + type.Name + "[" + index.PrintableString + "]"; } }
-        }
-
-        /**
-         * New C#-level object.
-         */
-        private class OTOpndNewobj : OTOpnd {
-            public ConstructorInfo ctor;
-            public OTOpnd[] args;
-
-            public static OTOpnd Make (ConstructorInfo ctor, OTOpnd[] args)
-            {
-                // newobj LSL_Float (x)  =>  x
-                if ((ctor.DeclaringType == typeof (LSL_Float)) && (args.Length == 1)) {
-                    Type ptype = ctor.GetParameters ()[0].ParameterType;
-                    if (ptype == typeof (string)) {
-                        return new OTOpndCast (typeof (double), args[0]);
-                    }
-                    return args[0];
-                }
-
-                // newobj LSL_Integer (x)  =>  x
-                if ((ctor.DeclaringType == typeof (LSL_Integer)) && (args.Length == 1)) {
-                    Type ptype = ctor.GetParameters ()[0].ParameterType;
-                    if (ptype == typeof (string)) {
-                        return new OTOpndCast (typeof (int), args[0]);
-                    }
-                    return args[0];
-                }
-
-                // newobj LSL_String (x)  =>  x
-                if ((ctor.DeclaringType == typeof (LSL_String)) && (args.Length == 1)) {
-                    return args[0];
-                }
-
-                // newobj LSL_Rotation (x, y, z, w)  =>  <x, y, z, w>
-                if ((ctor.DeclaringType == typeof (LSL_Rotation)) && (args.Length == 4)) {
-                    return new OTOpndRot (args[0], args[1], args[2], args[3]);
-                }
-
-                // newobj LSL_Vector (x, y, z)  =>  <x, y, z>
-                if ((ctor.DeclaringType == typeof (LSL_Vector)) && (args.Length == 3)) {
-                    return new OTOpndVec (args[0], args[1], args[2]);
-                }
-
-                // newobj LSL_Rotation (string)  => (rotation) string
-                if ((ctor.DeclaringType == typeof (LSL_Rotation)) && (args.Length == 1)) {
-                    return new OTOpndCast (typeof (LSL_Rotation), args[0]);
-                }
-
-                // newobj LSL_Vector (string)  => (rotation) string
-                if ((ctor.DeclaringType == typeof (LSL_Vector)) && (args.Length == 1)) {
-                    return new OTOpndCast (typeof (LSL_Vector), args[0]);
-                }
-
-                // newobj LSL_List (newarr object[0])  =>  [ ]
-                if ((ctor.DeclaringType == typeof (LSL_List)) && (args.Length == 1) && (args[0] is OTOpndNewarr)) {
-                    OTOpndNewarr arg0 = (OTOpndNewarr) args[0];
-                    if ((arg0.type == typeof (object)) && (arg0.index is OTOpndInt) && (((OTOpndInt) arg0.index).value == 0)) {
-                        OTOpndListIni listini = new OTOpndListIni ();
-                        listini.values = new OTOpnd[0];
-                        return listini;
-                    }
-                }
-
-                // something else, output as is
-                OTOpndNewobj it = new OTOpndNewobj ();
-                it.ctor = ctor;
-                it.args = args;
-                return it;
-            }
-
-            private OTOpndNewobj () { }
-
-            public override bool HasSideEffects {
-                get {
-                    foreach (OTOpnd arg in args) {
-                        if (arg.HasSideEffects) return true;
-                    }
-                    return false;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                foreach (OTOpnd arg in args) {
-                    arg.CountRefs (false);
-                }
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                for (int i = 0; i < args.Length; i ++) {
-                    args[i] = args[i].ReplaceOperand (oldopnd, newopnd, ref rc);
-                }
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndNewobj)) return false;
-                OTOpndNewobj otherno = (OTOpndNewobj) other;
-                if (otherno.ctor.DeclaringType != ctor.DeclaringType) return false;
-                if (otherno.args.Length != args.Length) return false;
-                for (int i = 0; i < args.Length; i ++) {
-                    if (!args[i].SameAs (otherno.args[i])) return false;
-                }
-                return true;
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    sb.Append ("newobj ");
-                    sb.Append (ctor.DeclaringType.Name);
-                    sb.Append (" (");
-                    bool first = true;
-                    foreach (OTOpnd arg in args) {
-                        if (!first) sb.Append (", ");
-                        sb.Append (arg.PrintableString);
-                        first = false;
-                    }
-                    sb.Append (')');
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Rotation value.
-         */
-        private class OTOpndRot : OTOpnd {
-            private OTOpnd x, y, z, w;
-
-            public OTOpndRot (OTOpnd x, OTOpnd y, OTOpnd z, OTOpnd w)
-            {
-                this.x = StripFloatCast (x);
-                this.y = StripFloatCast (y);
-                this.z = StripFloatCast (z);
-                this.w = StripFloatCast (w);
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects || w.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                x.CountRefs (false);
-                y.CountRefs (false);
-                z.CountRefs (false);
-                w.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                x = x.ReplaceOperand (oldopnd, newopnd, ref rc);
-                y = y.ReplaceOperand (oldopnd, newopnd, ref rc);
-                z = z.ReplaceOperand (oldopnd, newopnd, ref rc);
-                w = w.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndRot)) return false;
-                OTOpndRot otherv = (OTOpndRot) other;
-                return otherv.x.SameAs (x) && otherv.y.SameAs (y) && otherv.z.SameAs (z) && otherv.w.SameAs (w);
-            }
-
-            public override string PrintableString {
-                get {
-                    return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ", " + w.PrintableString + ">";
-                }
-            }
-        }
-
-        /**
-         * Static field.
-         */
-        private class OTOpndSField : OTOpnd {
-            private FieldInfo field;
-
-            public OTOpndSField (FieldInfo field)
-            {
-                this.field = field;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndSField)) return false;
-                OTOpndSField othersfield = (OTOpndSField) other;
-                return (field.Name == othersfield.field.Name) && (field.DeclaringType == othersfield.field.DeclaringType);
-            }
-
-            public override string PrintableString {
-                get {
-                    if (field.DeclaringType == typeof (ScriptBaseClass)) return field.Name;
-                    return field.DeclaringType.Name + "." + field.Name;
-                }
-            }
-        }
-
-        /**
-         * Call to string.Compare().
-         * See use cases in BinOpStr:
-         *   strcmp (a, b) ceq  0
-         *   (strcmp (a, b) ceq 0) xor 1  =>  we translate to:  strcmp (a, b) cne 0
-         *   strcmp (a, b) clt  0
-         *   strcmp (a, b) clt  1  // <=
-         *   strcmp (a, b) cgt  0
-         *   strcmp (a, b) cgt -1  // >=
-         * ...but then optimized by ScriptCollector if followed by br{false,true}:
-         *   ceq + xor 1 + brtrue  => bne.un
-         *   ceq + xor 1 + brfalse => beq
-         *   ceq + brtrue  => beq
-         *   ceq + brfalse => bne.un
-         *   cgt + brtrue  => bgt
-         *   cgt + brfalse => ble
-         *   clt + brtrue  => blt
-         *   clt + brfalse => bge
-         * So we end up with these cases:
-         *   strcmp (a, b) ceq  0
-         *   strcmp (a, b) cne  0
-         *   strcmp (a, b) clt  0
-         *   strcmp (a, b) clt  1
-         *   strcmp (a, b) cgt  0
-         *   strcmp (a, b) cgt -1
-         *   strcmp (a, b) beq    0
-         *   strcmp (a, b) bne.un 0
-         *   strcmp (a, b) bgt  0
-         *   strcmp (a, b) ble  0
-         *   strcmp (a, b) bgt -1
-         *   strcmp (a, b) ble -1
-         *   strcmp (a, b) blt  0
-         *   strcmp (a, b) bge  0
-         *   strcmp (a, b) blt  1
-         *   strcmp (a, b) bge  1
-         * ... so we pretty them up in OTOpndBinOp
-         */
-        private class OTOpndStrCmp : OTOpnd {
-            private static Dictionary<string,string> binops = InitBinops ();
-            private static Dictionary<string,string> InitBinops ()
-            {
-                Dictionary<string,string> d = new Dictionary<string,string> ();
-                d["ceq 0"]    = "ceq";
-                d["cne 0"]    = "cne";
-                d["clt 0"]    = "clt";
-                d["clt 1"]    = "cle";
-                d["cgt 0"]    = "cgt";
-                d["cgt -1"]   = "cge";
-                d["beq 0"]    = "ceq";
-                d["bne.un 0"] = "cne";
-                d["bgt 0"]    = "cgt";
-                d["ble 0"]    = "cle";
-                d["bgt -1"]   = "cge";
-                d["ble -1"]   = "clt";
-                d["blt 0"]    = "clt";
-                d["bge 0"]    = "cge";
-                d["blt 1"]    = "cle";
-                d["bge 1"]    = "cgt";
-                return d;
-            }
-
-            private OTOpnd arg0;
-            private OTOpnd arg1;
-
-            public OTOpndStrCmp (OTOpnd arg0, OTOpnd arg1)
-            {
-                this.arg0 = arg0;
-                this.arg1 = arg1;
-            }
-
-            /**
-             * Try to make something a script writer would recognize.
-             * If we can't, then we leave it as a call to xmrStringCompare().
-             *    this   = some strcmp(a,b)
-             *    opCode = hopefully some cxx or bxx from above table
-             *    rite   = hopefully some constant from above table
-             */
-            public OTOpnd MakeBinOp (MyOp opCode, OTOpnd rite)
-            {
-                if (!(rite is OTOpndInt)) return null;
-                int riteint = ((OTOpndInt) rite).value;
-                string key = opCode.name + ' ' + riteint;
-                string cxxopname;
-                if (!binops.TryGetValue (key, out cxxopname)) return null;
-                return OTOpndBinOp.Make (arg0, MyOp.GetByName (cxxopname), arg1);
-            }
-            public OTOpnd MakeUnOp (MyOp opCode)
-            {
-                if (opCode == MyOp.Brfalse) return OTOpndBinOp.Make (arg0, MyOp.Ceq, arg1);
-                if (opCode == MyOp.Brtrue)  return OTOpndBinOp.Make (arg0, MyOp.Cne, arg1);
-                return null;
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return false;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                arg0.CountRefs (writing);
-                arg1.CountRefs (writing);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                arg0 = arg0.ReplaceOperand (oldopnd, newopnd, ref rc);
-                arg1 = arg1.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndStrCmp)) return false;
-                return arg0.SameAs (((OTOpndStrCmp) other).arg0) && arg1.SameAs (((OTOpndStrCmp) other).arg1);
-            }
-
-            public override string PrintableString {
-                get {
-                    return "xmrStringCompare (" + arg0.PrintableString + ", " + arg1.PrintableString + ")";
-                }
-            }
-        }
-
-        /**
-         * Unary operator.
-         */
-        private class OTOpndUnOp : OTOpnd {
-            public MyOp opCode;
-            public OTOpnd value;
-
-            private static Dictionary<string,string> brfops = InitBrfOps ();
-            private static Dictionary<string,string> InitBrfOps ()
-            {
-                Dictionary<string,string> d = new Dictionary<string,string> ();
-                d["beq"]    = "cne";
-                d["bge"]    = "clt";
-                d["bgt"]    = "cle";
-                d["ble"]    = "cgt";
-                d["blt"]    = "cge";
-                d["bne.un"] = "ceq";
-                d["ceq"]    = "cne";
-                d["cge"]    = "clt";
-                d["cgt"]    = "cle";
-                d["cle"]    = "cgt";
-                d["clt"]    = "cge";
-                d["cne"]    = "ceq";
-                return d;
-            }
-
-            public static OTOpnd Make (MyOp opCode, OTOpnd value)
-            {
-                // (brfalse (brfalse (x)))  =>  (brtrue (x))
-                if ((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brfalse)) {
-                    ((OTOpndUnOp) value).opCode = MyOp.Brtrue;
-                    return value;
-                }
-
-                // (brfalse (brtrue (x)))  =>  (brfalse (x))
-                if ((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brtrue)) {
-                    ((OTOpndUnOp) value).opCode = MyOp.Brfalse;
-                    return value;
-                }
-
-                // (brtrue (brfalse (x)))  =>  (brfalse (x))
-                if ((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brfalse)) {
-                    return value;
-                }
-
-                // (brtrue (brtrue (x)))  =>  (brtrue (x))
-                if ((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp) value).opCode == MyOp.Brtrue)) {
-                    return value;
-                }
-
-                // (brfalse (x beq y))  =>  (x bne y)  etc
-                string brfop;
-                if ((opCode == MyOp.Brfalse) && (value is OTOpndBinOp) && brfops.TryGetValue (((OTOpndBinOp) value).opCode.name, out brfop)) {
-                    ((OTOpndBinOp) value).opCode = MyOp.GetByName (brfop);
-                    return value;
-                }
-
-                // (brtrue  (x beq y))  =>  (x beq y)  etc
-                if ((opCode == MyOp.Brtrue) && (value is OTOpndBinOp) && brfops.ContainsKey (((OTOpndBinOp) value).opCode.name)) {
-                    return value;
-                }
-
-                // strcmp() can be a special case
-                if (value is OTOpndStrCmp) {
-                    OTOpnd strcmp = ((OTOpndStrCmp) value).MakeUnOp (opCode);
-                    if (strcmp != null) return strcmp;
-                }
-
-                // nothing special, save opcode and value
-                OTOpndUnOp it = new OTOpndUnOp ();
-                it.opCode = opCode;
-                it.value  = value;
-                return it;
-            }
-
-            private OTOpndUnOp () { }
-
-            public override bool HasSideEffects {
-                get {
-                    return value.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                value.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndUnOp)) return false;
-                OTOpndUnOp otherop = (OTOpndUnOp) other;
-                return (opCode.ToString () == otherop.opCode.ToString ()) && value.SameAs (otherop.value);
-            }
-
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    sb.Append (opCode.source);
-                    sb.Append (' ');
-                    if (value is OTOpndBinOp) sb.Append ('(');
-                    sb.Append (value.PrintableString);
-                    if (value is OTOpndBinOp) sb.Append (')');
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /**
-         * Vector value.
-         */
-        private class OTOpndVec : OTOpnd {
-            private OTOpnd x, y, z;
-
-            public OTOpndVec (OTOpnd x, OTOpnd y, OTOpnd z)
-            {
-                this.x = StripFloatCast (x);
-                this.y = StripFloatCast (y);
-                this.z = StripFloatCast (z);
-            }
-
-            public override bool HasSideEffects {
-                get {
-                    return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects;
-                }
-            }
-
-            public override void CountRefs (bool writing)
-            {
-                x.CountRefs (false);
-                y.CountRefs (false);
-                z.CountRefs (false);
-            }
-
-            public override OTOpnd ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
-            {
-                if (SameAs (oldopnd)) {
-                    rc = true;
-                    return newopnd;
-                }
-                x = x.ReplaceOperand (oldopnd, newopnd, ref rc);
-                y = y.ReplaceOperand (oldopnd, newopnd, ref rc);
-                z = z.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return this;
-            }
-
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndVec)) return false;
-                OTOpndVec otherv = (OTOpndVec) other;
-                return otherv.x.SameAs (x) && otherv.y.SameAs (y) && otherv.z.SameAs (z);
-            }
-
-            public override string PrintableString {
-                get {
-                    return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ">";
-                }
-            }
-        }
-
-        /**
-         * Constants.
-         */
-        private class OTOpndDouble : OTOpnd {
-            public double value;
-            public OTOpndDouble (double value) { this.value = value; }
-            public override bool HasSideEffects { get { return false; } }
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndDouble)) return false;
-                return ((OTOpndDouble) other).value == value;
-            }
-            public override string PrintableString {
-                get {
-                    string s = value.ToString ();
-                    long i;
-                    if (long.TryParse (s, out i)) {
-                        s += ".0";
-                    }
-                    return s;
-                }
-            }
-        }
-        private class OTOpndFloat : OTOpnd {
-            public float value;
-            public OTOpndFloat (float value) { this.value = value; }
-            public override bool HasSideEffects { get { return false; } }
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndFloat)) return false;
-                return ((OTOpndFloat) other).value == value;
-            }
-            public override string PrintableString {
-                get {
-                    string s = value.ToString ();
-                    long i;
-                    if (long.TryParse (s, out i)) {
-                        s += ".0";
-                    }
-                    return s;
-                }
-            }
-        }
-        private class OTOpndInt : OTOpnd {
-            public int value;
-            public OTOpndInt (int value) { this.value = value; }
-            public override bool HasSideEffects { get { return false; } }
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndInt)) return false;
-                return ((OTOpndInt) other).value == value;
-            }
-            public override string PrintableString { get { return value.ToString (); } }
-        }
-        private class OTOpndNull : OTOpnd {
-            public override bool HasSideEffects { get { return false; } }
-            public override bool SameAs (OTOpnd other)
-            {
-                return other is OTOpndNull;
-            }
-            public override string PrintableString { get { return "undef"; } }
-        }
-        private class OTOpndString : OTOpnd {
-            public string value;
-            public OTOpndString (string value) { this.value = value; }
-            public override bool HasSideEffects { get { return false; } }
-            public override bool SameAs (OTOpnd other)
-            {
-                if (!(other is OTOpndString)) return false;
-                return ((OTOpndString) other).value == value;
-            }
-            public override string PrintableString {
-                get {
-                    StringBuilder sb = new StringBuilder ();
-                    TokenDeclInline.PrintParamString (sb, value);
-                    return sb.ToString ();
-                }
-            }
-        }
-
-        /****************************************\
-         *  Tokens what are in statement list.  *
-        \****************************************/
-
-        public abstract class OTStmt {
-
-            /**
-             * Increment reference counts.
-             */
-            public abstract void CountRefs ();
-
-            /**
-             * Strip out any of the behind-the-scenes code such as stack capture/restore.
-             * By default, there is no change.
-             */
-            public virtual bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                return false;
-            }
-
-            /**
-             * Replace the oldopnd operand with the newopnd operand if it is present.
-             * Return whether or not it was found and replaced.
-             */
-            public abstract bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd);
-
-            /**
-             * Detect and modify for do/for/if/while structures.
-             */
-            public virtual bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return false;
-            }
-
-            /**
-             * If this statement is the old statement, replace it with the given new statement.
-             * Also search any sub-ordinate statements.
-             * **NOTE**: minimally implemented to replace a Jump with a Break or Continue
-             */
-            public abstract OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt);
-
-            /**
-             * Print the statement out on the given printer with the given indenting.
-             * The first line is already indented, subsequent lines must be indented as given.
-             * This method should leave the printer at the end of the line.
-             */
-            public abstract void PrintStmt (TextWriter twout, string indent);
-
-            /**
-             * Strip all statements following this statement
-             * because this statement jumps somewhere.
-             */
-            protected bool StripStuffForTerminal (LinkedListNode<OTStmt> link)
-            {
-                // strip all statements following jump until seeing some label
-                bool rc = false;
-                if (link != null) {
-                    LinkedListNode<OTStmt> nextlink;
-                    while ((nextlink = link.Next) != null) {
-                        if (nextlink.Value is OTStmtLabel) break;
-                        nextlink.List.Remove (nextlink);
-                        rc = true;
-                    }
-                }
-                return rc;
-            }
-        }
-
-        /**************************\
-         *  Primitive statements  *
-        \**************************/
-
-        /**
-         * Begin catch block (catch).
-         */
-        private class OTStmtBegCatBlk : OTStmt {
-            public OTStmtBegExcBlk tryblock;
-            public OTStmtBlock catchblock;
-
-            private Type excType;
-
-            public OTStmtBegCatBlk (Type excType)
-            {
-                this.excType = excType;
-            }
-
-            public override void CountRefs ()
-            {
-                catchblock.CountRefs ();
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                return catchblock.StripStuff (null);
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return catchblock.ReplaceOperand (oldopnd, newopnd);
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return catchblock.DetectDoForIfWhile (link);
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                catchblock = (OTStmtBlock) catchblock.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            /**
-             * Print out the catch block including its enclosed statements.
-             */
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("catch (" + excType.Name + ") ");
-                catchblock.PrintStmt (twout, indent);
-            }
-        }
-
-        /**
-         * Begin exception block (try).
-         */
-        private class OTStmtBegExcBlk : OTStmt {
-
-            // statements within the try { } not including any catch or finally
-            public OTStmtBlock tryblock;
-
-            // list of all catch { } blocks associated with this try { }
-            public LinkedList<OTStmtBegCatBlk> catches = new LinkedList<OTStmtBegCatBlk> ();
-
-            // possible single finally { } associated with this try
-            public OTStmtBegFinBlk finblock;  // might be null
-
-            public override void CountRefs ()
-            {
-                tryblock.CountRefs ();
-                foreach (OTStmtBegCatBlk catblock in catches) {
-                    catblock.CountRefs ();
-                }
-                if (finblock != null) finblock.CountRefs ();
-            }
-
-            /**
-             * Strip behind-the-scenes info from all the sub-blocks.
-             */
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // strip behind-the-scenes info from all the sub-blocks.
-                bool rc = tryblock.StripStuff (null);
-                foreach (OTStmtBegCatBlk catblk in catches) {
-                    rc |= catblk.StripStuff (null);
-                }
-                if (finblock != null) rc |= finblock.StripStuff (null);
-                if (rc) return true;
-
-                // change:
-                //    try {
-                //       ...
-                //    }
-                // to:
-                //    {
-                //       ...
-                //    }
-                // note that an empty catch () { } has meaning so can't be stripped
-                // empty finally { } blocks strips itself from the try
-                if ((catches.Count == 0) && (finblock == null) && (link != null)) {
-                    link.List.AddAfter (link, tryblock);
-                    tryblock = null;
-                    link.List.Remove (link);
-                    return true;
-                }
-
-                return false;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = tryblock.ReplaceOperand (oldopnd, newopnd);
-                foreach (OTStmtBegCatBlk catblk in catches) {
-                    rc |= catblk.ReplaceOperand (oldopnd, newopnd);
-                }
-                if (finblock != null) rc |= finblock.ReplaceOperand (oldopnd, newopnd);
-                return rc;
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                bool rc = tryblock.DetectDoForIfWhile (link);
-                foreach (OTStmtBegCatBlk catblk in catches) {
-                    rc |= catblk.DetectDoForIfWhile (link);
-                }
-                if (finblock != null) rc |= finblock.DetectDoForIfWhile (link);
-                return rc;
-            }
-
-            /**
-             * Assume we will never try to replace the try block itself.
-             * But go through all our sub-ordinates statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                tryblock = (OTStmtBlock) tryblock.ReplaceStatement (oldstmt, newstmt);
-                for (LinkedListNode<OTStmtBegCatBlk> catlink = catches.First; catlink != null; catlink = catlink.Next) {
-                    catlink.Value = (OTStmtBegCatBlk) catlink.Value.ReplaceStatement (oldstmt, newstmt);
-                }
-                if (finblock != null) finblock = (OTStmtBegFinBlk) finblock.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            /**
-             * Print out the try block including its enclosed statements.
-             * And since the try is the only thing pushed to the outer block,
-             * we also print out all the catch and finally blocks.
-             */
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("try ");
-                tryblock.PrintStmt (twout, indent);
-                foreach (OTStmtBegCatBlk catblk in catches) {
-                    twout.Write (' ');
-                    catblk.PrintStmt (twout, indent);
-                }
-                if (finblock != null) {
-                    twout.Write (' ');
-                    finblock.PrintStmt (twout, indent);
-                }
-            }
-        }
-
-        /**
-         * Begin finally block (finally).
-         */
-        private class OTStmtBegFinBlk : OTStmt {
-            public OTStmtBegExcBlk tryblock;
-            public OTStmtBlock finblock;
-
-            public override void CountRefs ()
-            {
-                finblock.CountRefs ();
-            }
-
-            /**
-             * Strip behind-the-scene parts from the finally block.
-             */
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // strip behind-the-scenes parts from finally block itself
-                if (finblock.StripStuff (null)) return true;
-
-                // if finblock is empty, delete the finally from the try
-                if (finblock.blkstmts.Count == 0) {
-                    tryblock.finblock = null;
-                    return true;
-                }
-
-                return false;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return finblock.ReplaceOperand (oldopnd, newopnd);
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return finblock.DetectDoForIfWhile (link);
-            }
-
-            /**
-             * Assume we will never try to replace the finally block itself.
-             * But go through all our sub-ordinates statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                finblock = (OTStmtBlock) finblock.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            /**
-             * Print out the finally block including its enclosed statements.
-             */
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("finally ");
-                finblock.PrintStmt (twout, indent);
-            }
-        }
-
-        /**
-         * Simple if jump/break/continue statement.
-         */
-        private class OTStmtCond : OTStmt {
-            public OTOpnd valu;
-            public OTStmt stmt;  // jump, break, continue only
-
-            public OTStmtCond (OTOpnd valu, OTStmt stmt)
-            {
-                this.valu = valu;
-                this.stmt = stmt;
-            }
-
-            public override void CountRefs ()
-            {
-                valu.CountRefs (false);
-                stmt.CountRefs ();
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // we assume that callMode is always CallMode_NORMAL, ie, not doing a stack capture or restore
-                // so the 'if (arg$0.callMode bne.un 0) ...' is deleted
-                // and the 'if (arg$0.callMode bne.un 1) ...' becomes unconditional
-                // it can also be __xmrinst.callMode instead of arg$0
-                if (valu is OTOpndBinOp) {
-                    OTOpndBinOp binop = (OTOpndBinOp) valu;
-                    if ((binop.left is OTOpndField) && (binop.opCode.ToString () == "bne.un") && (binop.rite is OTOpndInt)) {
-                        OTOpndField leftfield = (OTOpndField) binop.left;
-                        if (leftfield.field.Name == _callMode) {
-                            bool ok = false;
-                            if (leftfield.obj is OTOpndArg) {
-                                ok = ((OTOpndArg) leftfield.obj).index == 0;
-                            }
-                            if (leftfield.obj is OTOpndLocal) {
-                                ok = ((OTOpndLocal) leftfield.obj).local.name.StartsWith (_xmrinstlocal);
-                            }
-                            if (ok) {
-                                OTOpndInt riteint = (OTOpndInt) binop.rite;
-
-                                // delete 'if ((arg$0).callMode bne.un 0) ...'
-                                if (riteint.value == XMRInstAbstract.CallMode_NORMAL) {
-                                    link.List.Remove (link);
-                                    return true;
-                                }
-
-                                // make 'if ((arg$0).callMode bne.un 1) ...' unconditional
-                                if (riteint.value == XMRInstAbstract.CallMode_SAVE) {
-                                    link.Value = stmt;
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
-
-                // similarly we assume that doGblInit is always 0 to eliminate the code at beginning of default state_entry()
-                // so the 'if (brfalse __xmrinst.doGblInit) ...' is made unconditional
-                if (valu is OTOpndUnOp) {
-                    OTOpndUnOp unop = (OTOpndUnOp) valu;
-                    if ((unop.opCode == MyOp.Brfalse) && (unop.value is OTOpndField)) {
-                        OTOpndField valuefield = (OTOpndField) unop.value;
-                        if (valuefield.field.Name == _doGblInit) {
-                            bool ok = false;
-                            if (valuefield.obj is OTOpndLocal) {
-                                ok = ((OTOpndLocal) valuefield.obj).local.name.StartsWith (_xmrinstlocal);
-                            }
-                            if (ok) {
-
-                                // make 'if (brfalse __xmrinst.doGblInit) ...' unconditional
-                                link.Value = stmt;
-                                return true;
-                            }
-                        }
-                    }
-                }
-
-                return false;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = stmt.ReplaceOperand (oldopnd, newopnd);
-                valu = valu.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            /**
-             * Maybe this simple if statement is part of a script-level if/then/else statement.
-             */
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return OTStmtIf.Detect (link);
-            }
-
-            /**
-             * Assume we won't replace the if statement itself.
-             * But search all our sub-ordinate statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                stmt = stmt.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("if (" + StripBrtrue (valu).PrintableString + ") ");
-                stmt.PrintStmt (twout, indent);
-            }
-
-            /**
-             * Scan forward for a given label definition.
-             * Put intervening statements in a statement block.
-             * @param link = start scanning after this statement
-             * @param label = look for this label definition
-             * @param block = where to return intervening statement block
-             * @returns null: label definition not found
-             *          else: label definition statement
-             */
-            private static LinkedListNode<OTStmt> ScanForLabel (LinkedListNode<OTStmt> link,
-                        OTLabel label, out OTStmtBlock block)
-            {
-                block = new OTStmtBlock ();
-                while ((link = link.Next) != null) {
-                    if (link.Value is OTStmtLabel) {
-                        if (((OTStmtLabel) link.Value).label == label) break;
-                    }
-                    block.blkstmts.AddLast (link.Value);
-                }
-                return link;
-            }
-
-            /**
-             * Strip statements after link up to and including donelink.
-             */
-            private static void StripInterveningStatements (LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
-            {
-                LinkedListNode<OTStmt> striplink;
-                do {
-                    striplink = link.Next;
-                    striplink.List.Remove (striplink);
-                } while (striplink != donelink);
-            }
-        }
-
-        /**
-         * Jump to a label.
-         */
-        private class OTStmtJump : OTStmt {
-            public OTLabel label;
-
-            public static OTStmt Make (OTLabel label)
-            {
-                // jumps to __retlbl are return statements
-                // note that is is safe to say it is a valueless return because
-                // valued returns are done with this construct:
-                //    __retval = ....;
-                //    jump __retlbl;
-                // and those __retval = statements have been changed to return statements already
-                if (label.name.StartsWith (_retlbl)) return new OTStmtRet (null);
-
-                // other jumps are really jumps
-                OTStmtJump it = new OTStmtJump ();
-                it.label = label;
-                return it;
-            }
-
-            private OTStmtJump () { }
-
-            public override void CountRefs ()
-            {
-                label.lbljumps ++;
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                if (link == null) return false;
-
-                // strip statements following unconditional jump until next label
-                bool rc = StripStuffForTerminal (link);
-
-                // if we (now) have:
-                //      jump label;
-                //   @label;
-                // ... delete this jump
-                if (link.Next != null) {
-                    OTStmtLabel nextlabel = (OTStmtLabel) link.Next.Value;
-                    if (nextlabel.label == label) {
-                        link.List.Remove (link);
-                        rc = true;
-                    }
-                }
-
-                return rc;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return false;
-            }
-
-            /**
-             * This is actually what ReplaceStatement() is currently used for.
-             * It replaces a jump with a break or a continue.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                if ((oldstmt is OTStmtJump) && (((OTStmtJump) oldstmt).label == label)) return newstmt;
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("jump " + label.PrintableName + ';');
-            }
-        }
-
-        /**
-         * Label definition point.
-         */
-        private class OTStmtLabel : OTStmt {
-            public OTLabel label;
-
-            private OTDecompile decompile;
-
-            public static void AddLast (OTDecompile decompile, OTLabel label)
-            {
-                OTStmtLabel it = new OTStmtLabel ();
-                it.label = label;
-                it.decompile = decompile;
-                decompile.AddLastStmt (it);
-            }
-
-            private OTStmtLabel () { }
-
-            public override void CountRefs ()
-            {
-                // don't increment label.lbljumps
-                // cuz we don't want the positioning
-                // to count as a reference, only jumps
-                // to the label should count
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // if label has nothing jumping to it, remove the label
-                if (link != null) {
-                    label.lbljumps = 0;
-                    decompile.topBlock.CountRefs ();
-                    if (label.lbljumps == 0) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return false;
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                if (OTStmtDo.Detect  (link)) return true;
-                if (OTStmtFor.Detect (link, true)) return true;
-                if (OTStmtFor.Detect (link, false)) return true;
-                return false;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("@" + label.PrintableName + ';');
-            }
-        }
-
-        /**
-         * Return with or without value.
-         */
-        private class OTStmtRet : OTStmt {
-            public OTOpnd value;  // might be null
-
-            public OTStmtRet (OTOpnd value)
-            {
-                this.value = value;
-            }
-
-            public override void CountRefs ()
-            {
-                if (value != null) value.CountRefs (false);
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                return StripStuffForTerminal (link);
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                if (value == null) {
-                    twout.Write ("return;");
-                } else {
-                    twout.Write ("return " + value.PrintableString + ';');
-                }
-            }
-        }
-
-        /**
-         * Store value in variable.
-         */
-        private class OTStmtStore : OTStmt {
-            public OTOpnd varwr;
-            public OTOpnd value;
-
-            private OTDecompile decompile;
-
-            public static void AddLast (OTDecompile decompile, OTOpnd varwr, OTOpnd value)
-            {
-                OTStmtStore it = new OTStmtStore (varwr, value, decompile);
-                decompile.AddLastStmt (it);
-            }
-
-            public OTStmtStore (OTOpnd varwr, OTOpnd value, OTDecompile decompile)
-            {
-                this.varwr     = varwr;
-                this.value     = value;
-                this.decompile = decompile;
-            }
-
-            public override void CountRefs ()
-            {
-                varwr.CountRefs (true);
-                value.CountRefs (false);
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // strip out stores to __mainCallNo
-                if (varwr is OTOpndLocal) {
-                    OTOpndLocal local = (OTOpndLocal) varwr;
-                    if (local.local.name.StartsWith (_mainCallNo)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                // strip out stores to local vars where the var is not read
-                // but convert the value to an OTStmtVoid in case it is a call
-                if (varwr is OTOpndLocal) {
-                    OTOpndLocal local = (OTOpndLocal) varwr;
-                    local.local.nlclreads = 0;
-                    decompile.topBlock.CountRefs ();
-                    if (local.local.nlclreads == 0) {
-                        OTStmt voidstmt = OTStmtVoid.Make (value);
-                        if (voidstmt == null) link.List.Remove (link);
-                                         else link.Value = voidstmt;
-                        return true;
-                    }
-                }
-
-                // strip out bla = newobj HeapTrackerList (...);
-                if (value is OTOpndNewobj) {
-                    OTOpndNewobj valueno = (OTOpndNewobj) value;
-                    if (valueno.ctor.DeclaringType == typeof (HeapTrackerList)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                // strip out bla = newobj HeapTrackerObject (...);
-                if (value is OTOpndNewobj) {
-                    OTOpndNewobj valueno = (OTOpndNewobj) value;
-                    if (valueno.ctor.DeclaringType == typeof (HeapTrackerObject)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                // strip out bla = newobj HeapTrackerString (...);
-                if (value is OTOpndNewobj) {
-                    OTOpndNewobj valueno = (OTOpndNewobj) value;
-                    if (valueno.ctor.DeclaringType == typeof (HeapTrackerString)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                // convert tmp$n = bla bla;
-                //         ....  tmp$n  ....;
-                // to
-                //         ....  bla bla  ....;
-                // gets rid of vast majority of temps
-                if (varwr is OTOpndLocal) {
-                    OTOpndLocal temp = (OTOpndLocal) varwr;
-                    if (temp.local.name.StartsWith ("tmp$")) {
-                        temp.local.nlclreads  = 0;
-                        temp.local.nlclwrites = 0;
-                        decompile.topBlock.CountRefs ();
-                        if ((temp.local.nlclreads == 1) && (temp.local.nlclwrites == 1) && (link.Next != null)) {
-                            OTStmt nextstmt = link.Next.Value;
-                            if (!(nextstmt is OTStmtBlock)) {
-                                if (nextstmt.ReplaceOperand (varwr, value)) {
-                                    link.List.Remove (link);
-                                    return true;
-                                }
-                            }
-                        }
-
-                        // also try to convert:
-                        //    tmp$n = ... asdf ...  << we are here (link)
-                        //    lcl = tmp$n;          << nextstore
-                        //    ... qwer tmp$n ...
-                        //    ... no further references to tmp$n
-                        // to:
-                        //    lcl = ... asdf ...
-                        //    ... qwer lcl ...
-                        if ((temp.local.nlclreads == 2) && (temp.local.nlclwrites == 1) &&
-                                (link.Next != null) && (link.Next.Value is OTStmtStore)) {
-                            OTStmtStore nextstore = (OTStmtStore) link.Next.Value;
-                            if ((nextstore.varwr is OTOpndLocal) && (nextstore.value is OTOpndLocal) && (link.Next.Next != null)) {
-                                OTOpndLocal localopnd = (OTOpndLocal) nextstore.varwr;
-                                OTOpndLocal tempopnd  = (OTOpndLocal) nextstore.value;
-                                if (tempopnd.local == temp.local) {
-                                    OTStmt finalstmt = link.Next.Next.Value;
-                                    if (finalstmt.ReplaceOperand (tempopnd, localopnd)) {
-                                        nextstore.value = value;
-                                        link.List.Remove (link);
-                                        return true;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-
-                // convert:
-                //    dup$n = ... asdf ...  << we are here
-                //    lcl = dup$n;
-                //    ... qwer dup$n ...
-                //    ... no further references to dup$n
-                // to:
-                //    lcl = ... asdf ...
-                //    ... qwer lcl ...
-                if ((varwr is OTOpndDup) && (link != null)) {
-                    OTOpndDup vardup = (OTOpndDup) varwr;
-                    LinkedListNode<OTStmt> nextlink = link.Next;
-                    vardup.ndupreads = 0;
-                    decompile.topBlock.CountRefs ();
-                    if ((vardup.ndupreads == 2) && (nextlink != null) && (nextlink.Value is OTStmtStore)) {
-
-                        // point to the supposed lcl = dup$n statement
-                        OTStmtStore nextstore = (OTStmtStore) nextlink.Value;
-                        LinkedListNode<OTStmt> nextlink2 = nextlink.Next;
-                        if ((nextstore.varwr is OTOpndLocal) && (nextstore.value == vardup) && (nextlink2 != null)) {
-
-                            // get the local var being written and point to the ... qwer dup$n ... statement
-                            OTOpndLocal varlcl = (OTOpndLocal) nextstore.varwr;
-                            OTStmt nextstmt2 = nextlink2.Value;
-
-                            // try to replace dup$n in qwer with lcl
-                            if (nextstmt2.ReplaceOperand (vardup, varlcl)) {
-
-                                // successful, replace dup$n in asdf with lcl
-                                // and delete the lcl = dup$n statement
-                                varwr = varlcl;
-                                nextlink.List.Remove (nextlink);
-                                return true;
-                            }
-                        }
-                    }
-                }
-
-                // convert:
-                //    dup$n = ... asdf ...  << we are here
-                //    ... qwer dup$n ...
-                //    ... no further references to dup$n
-                // to:
-                //    ... qwer ... asdf ... ...
-                if ((varwr is OTOpndDup) && (link != null)) {
-                    OTOpndDup vardup = (OTOpndDup) varwr;
-                    LinkedListNode<OTStmt> nextlink = link.Next;
-                    vardup.ndupreads = 0;
-                    decompile.topBlock.CountRefs ();
-                    if ((vardup.ndupreads == 1) && (nextlink != null)) {
-
-                        // point to the ... qwer dup$n ... statement
-                        OTStmt nextstmt = nextlink.Value;
-
-                        // try to replace dup$n in qwer with ... asdf ...
-                        if (nextstmt.ReplaceOperand (vardup, value)) {
-
-                            // successful, delete the dup$n = ... asdf ... statement
-                            link.List.Remove (link);
-                            return true;
-                        }
-                    }
-                }
-
-                // look for list initialization [ ... ]
-                if (OTOpndListIni.Detect (link)) return true;
-
-                // __xmrinst = (XMRInstAbstract) arg$0 indicates this is an event handler
-                // so strip it out and set the flag
-                if ((varwr is OTOpndLocal) && (value is OTOpndCast)) {
-                    OTOpndLocal lcl  = (OTOpndLocal) varwr;
-                    OTOpndCast  cast = (OTOpndCast) value;
-                    if (lcl.local.name.StartsWith (_xmrinstlocal) && (cast.value is OTOpndArg)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                // local = [ (optional cast) ] __xmrinst.ehArgs[n] is a definition of event handler arg #n
-                // if found, make it event handler arg list definition
-                OTOpnd valuenocast = value;
-                if (valuenocast is OTOpndCast) valuenocast = ((OTOpndCast) value).value;
-                if ((varwr is OTOpndLocal) && (valuenocast is OTOpndArrayElem)) {
-                    OTOpndArrayElem array = (OTOpndArrayElem) valuenocast;
-                    if ((array.array is OTOpndField) && (array.index is OTOpndInt)) {
-                        OTOpndField arrayfield = (OTOpndField) array.array;
-                        if ((arrayfield.obj is OTOpndLocal) &&
-                                ((OTOpndLocal) arrayfield.obj).local.name.StartsWith (_xmrinstlocal) &&
-                                (arrayfield.field.Name == _ehArgs)) {
-                            int index = ((OTOpndInt) array.index).value;
-                            decompile.eharglist[index] = ((OTOpndLocal) varwr).local;
-                            link.List.Remove (link);
-                            return true;
-                        }
-                    }
-                }
-
-                // __retval$n = ...;  =>  return ...;
-                if (varwr is OTOpndLocal) {
-                    OTOpndLocal lcl = (OTOpndLocal) varwr;
-                    if (lcl.local.name.StartsWith (_retval)) {
-                        link.Value = new OTStmtRet (value);
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                // print x = x + 1 as x += 1, but don't print x = x < 3 as x <= 3
-                if (value is OTOpndBinOp) {
-                    OTOpndBinOp valuebo = (OTOpndBinOp) value;
-                    if (varwr.SameAs (valuebo.left) && " add and div mul or rem shl shr sub xor ".Contains (' ' + valuebo.opCode.name + ' ')) {
-                        twout.Write (varwr.PrintableString + ' ' + valuebo.opCode.source + "= " + valuebo.rite.PrintableString + ';');
-                        return;
-                    }
-                }
-
-                twout.Write (varwr.PrintableString + " = " + value.PrintableString + ';');
-            }
-        }
-
-        /**
-         * Dispatch to a table of labels.
-         */
-        private class OTStmtSwitch : OTStmt {
-            private OTOpnd index;
-            private OTLabel[] labels;
-
-            public OTStmtSwitch (OTOpnd index, OTLabel[] labels)
-            {
-                this.index  = index;
-                this.labels = labels;
-            }
-
-            public override void CountRefs ()
-            {
-                index.CountRefs (false);
-                foreach (OTLabel label in labels) {
-                    label.lbljumps ++;
-                }
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                if (index != null) index = index.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("switch (" + index.PrintableString + ") {\n");
-                for (int i = 0; i < labels.Length; i ++) {
-                    twout.Write (indent + INDENT + "case " + i + ": jump " + labels[i].name + ";\n");
-                }
-                twout.Write (indent + '}');
-            }
-        }
-
-        /**
-         * Throw an exception.
-         */
-        private class OTStmtThrow : OTStmt {
-            private OTOpnd value;
-            private OTDecompile decompile;
-
-            public OTStmtThrow (OTOpnd value, OTDecompile decompile)
-            {
-                this.value = value;
-                this.decompile = decompile;
-            }
-
-            public override void CountRefs ()
-            {
-                value.CountRefs (false);
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                return StripStuffForTerminal (link);
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                if (value != null) value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                // throw newobj ScriptUndefinedStateException ("x")  =>  state x
-                if (value is OTOpndNewobj) {
-                    OTOpndNewobj valueno = (OTOpndNewobj) value;
-                    if ((valueno.ctor.DeclaringType == typeof (ScriptUndefinedStateException)) &&
-                        (valueno.args.Length == 1) && (valueno.args[0] is OTOpndString)) {
-                        OTOpndString arg0 = (OTOpndString) valueno.args[0];
-                        twout.Write ("state " + arg0.value + ";  /* throws undefined state exception */");
-                        return;
-                    }
-                }
-
-                // throw newobj ScriptChangeStateException (n)  =>  state n
-                if (value is OTOpndNewobj) {
-                    OTOpndNewobj valueno = (OTOpndNewobj) value;
-                    if ((valueno.ctor.DeclaringType == typeof (ScriptChangeStateException)) &&
-                        (valueno.args.Length == 1) && (valueno.args[0] is OTOpndInt)) {
-                        OTOpndInt arg0 = (OTOpndInt) valueno.args[0];
-                        twout.Write ("state " + decompile.scriptObjCode.stateNames[arg0.value] + ';');
-                        return;
-                    }
-                }
-
-                // throwing something else, output as is
-                twout.Write ("throw " + value.PrintableString + ';');
-            }
-        }
-
-        /**
-         * Call with void return, or really anything that we discard the value of after computing it.
-         */
-        private class OTStmtVoid : OTStmt {
-            private OTOpnd value;
-
-            public static void AddLast (OTDecompile decompile, OTOpnd value)
-            {
-                OTStmt it = OTStmtVoid.Make (value);
-                if (it != null) decompile.AddLastStmt (it);
-            }
-
-            public static OTStmt Make (OTOpnd value)
-            {
-                if (!value.HasSideEffects) return null;
-                OTStmtVoid it = new OTStmtVoid ();
-                it.value = value;
-                return it;
-            }
-
-            private OTStmtVoid () { }
-
-            public override void CountRefs ()
-            {
-                value.CountRefs (false);
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                value = value.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // strip out calls to CheckRunQuick() and CheckRunStack()
-                if (value is OTOpndCall) {
-                    OTOpndCall call = (OTOpndCall) value;
-                    MethodInfo method = call.method;
-                    if ((method.Name == _checkRunQuick) || (method.Name == _checkRunStack)) {
-                        link.List.Remove (link);
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write (value.PrintableString + ';');
-            }
-        }
-
-        /***************************\
-         *  Structured statements  *
-        \***************************/
-
-        /**
-         * Block of statements.
-         */
-        private class OTStmtBlock : OTStmt {
-            public LinkedList<OTStmt> blkstmts = new LinkedList<OTStmt> ();
-
-            public override void CountRefs ()
-            {
-                foreach (OTStmt stmt in blkstmts) {
-                    stmt.CountRefs ();
-                }
-            }
-
-            /**
-             * Scrub out all references to behind-the-scenes parts and simplify.
-             */
-            public override bool StripStuff (LinkedListNode<OTStmt> link)
-            {
-                // loop through all sub-statements to strip out behind-the-scenes references
-                bool rc = false;
-            loop:
-                for (LinkedListNode<OTStmt> stmtlink = blkstmts.First; stmtlink != null; stmtlink = stmtlink.Next) {
-                    if (stmtlink.Value.StripStuff (stmtlink)) {
-                        rc = true;
-                        goto loop;
-                    }
-                }
-                if (rc) return true;
-
-                // try to merge this block into outer block
-                // change:
-                //   {
-                //       ...
-                //       {          << link points here
-                //           ...
-                //       }
-                //       ...
-                //   }
-                // to:
-                //   {
-                //       ...
-                //       ...
-                //       ...
-                //   }
-                if (link != null) {
-                    LinkedListNode<OTStmt> nextlink;
-                    while ((nextlink = blkstmts.Last) != null) {
-                        nextlink.List.Remove (nextlink);
-                        link.List.AddAfter (link, nextlink);
-                    }
-                    link.List.Remove (link);
-                    return true;
-                }
-
-                return rc;
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = false;
-                foreach (OTStmt stmt in blkstmts) {
-                    rc |= stmt.ReplaceOperand (oldopnd, newopnd);
-                }
-                return rc;
-            }
-
-            /**
-             * Check each statement in the block to see if it starts a do/for/if/while statement.
-             */
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                bool rc = false;
-            loop:
-                for (link = blkstmts.First; link != null; link = link.Next) {
-                    if (link.Value.DetectDoForIfWhile (link)) {
-                        rc = true;
-                        goto loop;
-                    }
-                }
-                return rc;
-            }
-
-            /**
-             * Assume we will never try to replace the block itself.
-             * But go through all our sub-ordinates statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                for (LinkedListNode<OTStmt> childlink = blkstmts.First; childlink != null; childlink = childlink.Next) {
-                    childlink.Value = childlink.Value.ReplaceStatement (oldstmt, newstmt);
-                }
-                return this;
-            }
-
-            /**
-             * Print out the block including its enclosed statements.
-             */
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                switch (blkstmts.Count) {
-                    case 0: {
-                        twout.Write ("{ }");
-                        break;
-                    }
-                    ////case 1: {
-                    ////    blkstmts.First.Value.PrintStmt (twout, indent);
-                    ////    break;
-                    ////}
-                    default: {
-                        twout.Write ('{');
-                        PrintBodyAndEnd (twout, indent);
-                        break;
-                    }
-                }
-            }
-
-            public void PrintBodyAndEnd (TextWriter twout, string indent)
-            {
-                string newindent = indent + INDENT;
-                foreach (OTStmt stmt in blkstmts) {
-                    twout.Write ('\n' + indent);
-                    if (!(stmt is OTStmtLabel)) twout.Write (INDENT);
-                                      else twout.Write (LABELINDENT);
-                    stmt.PrintStmt (twout, newindent);
-                }
-                twout.Write ('\n' + indent + '}');
-            }
-        }
-
-        /**
-         * 'do' statement.
-         */
-        private class OTStmtDo : OTStmt {
-            private OTOpnd      dotest;
-            private OTStmtBlock dobody;
-
-            /**
-             * See if we have a do loop...
-             *   @doloop_<suffix>;     << link points here
-             *     ... <dobody> ...
-             *     [ if (dotest) ] jump doloop_<suffix>;
-             */
-            public static bool Detect (LinkedListNode<OTStmt> link)
-            {
-                // see if we have label starting with 'doloop_'
-                OTLabel looplabel = ((OTStmtLabel) link.Value).label;
-                if (!looplabel.name.StartsWith (_doLoop)) return false;
-
-                // good chance we have a do loop
-                OTStmtDo it = new OTStmtDo ();
-
-                // scan ahead looking for the terminating cond/jump loop
-                // also gather up the statements for the do body block
-                it.dobody = new OTStmtBlock ();
-                LinkedListNode<OTStmt> nextlink;
-                for (nextlink = link.Next; nextlink != null; nextlink = nextlink.Next) {
-                    OTStmt nextstmt = nextlink.Value;
-
-                    // add statement to do body
-                    it.dobody.blkstmts.AddLast (nextlink.Value);
-
-                    // check for something what jumps to loop label
-                    // that gives us the end of the loop
-                    OTStmt maybejump = nextstmt;
-                    if (nextstmt is OTStmtCond) {
-                        maybejump = ((OTStmtCond) nextstmt).stmt;
-                    }
-                    if ((maybejump is OTStmtJump) && (((OTStmtJump) maybejump).label == looplabel)) {
-                        break;
-                    }
-                }
-
-                // make sure we found the jump back to the loop label
-                if (nextlink == null) return false;
-
-                // remove all statements from caller's block including the continue label if any
-                // but leave the break label alone it will be removed later if unreferenced
-                // and leave the initial loop label intact for now
-                for (LinkedListNode<OTStmt> remlink = null; (remlink = link.Next) != null;) {
-                    link.List.Remove (remlink);
-                    if (remlink == nextlink) break;
-                }
-
-                // take test condition from last statement of body
-                // it should be an cond/jump or just a jump to the loop label
-                LinkedListNode<OTStmt> lastlink = it.dobody.blkstmts.Last;
-                OTStmt laststmt = lastlink.Value;
-                if (laststmt is OTStmtCond) {
-                    it.dotest = ((OTStmtCond) laststmt).valu;
-                } else {
-                    it.dotest = new OTOpndInt (1);
-                }
-                lastlink.List.Remove (lastlink);
-
-                // finally replace the loop label with the whole do statement
-                link.Value = it;
-
-                // tell caller we made a change
-                return true;
-            }
-
-            public override void CountRefs ()
-            {
-                if (dotest != null) dotest.CountRefs (false);
-                if (dobody != null) dobody.CountRefs ();
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return dobody.ReplaceOperand (oldopnd, newopnd);
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return dobody.DetectDoForIfWhile (link);
-            }
-
-            /**
-             * Assume we won't replace the do statement itself.
-             * But search all our sub-ordinate statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                dobody = (OTStmtBlock) dobody.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                // output do body
-                twout.Write ("do ");
-                dobody.PrintStmt (twout, indent);
-
-                // output while part
-                twout.Write (" while (" + StripBrtrue (dotest).PrintableString + ");");
-            }
-        }
-
-        /**
-         * 'for' or 'while' statement.
-         */
-        private class OTStmtFor : OTStmt {
-            private bool        iswhile;
-            private OTOpnd      fortest;
-            private OTStmtBlock forbody;
-            private OTStmt      forinit;
-            private OTStmt      forstep;
-
-            /**
-             * See if we have a for or while loop...
-             *     <forinit>
-             *   @forloop_<suffix>;     << link points here
-             *     [ if (<fortest>) jump forbreak_<suffix>; ]
-             *     ... <forbody> ...
-             *     jump forloop_<suffix>;
-             *   [ @forbreak_<suffix>; ]
-             */
-            public static bool Detect (LinkedListNode<OTStmt> link, bool iswhile)
-            {
-                string loopname  = iswhile ? _whileLoop  : _forLoop;
-                string breakname = iswhile ? _whileBreak : _forBreak;
-
-                // see if we have label starting with 'forloop_'
-                OTLabel looplabel = ((OTStmtLabel) link.Value).label;
-                if (!looplabel.name.StartsWith (loopname)) return false;
-
-                // good chance we have a for loop
-                OTStmtFor it = new OTStmtFor ();
-                it.iswhile = iswhile;
-
-                // all labels end with this suffix
-                string suffix = looplabel.name.Substring (loopname.Length);
-
-                // scan ahead looking for the 'jump forloop_<suffix>;' statement
-                // also gather up the statements for the for body block
-                it.forbody = new OTStmtBlock ();
-                LinkedListNode<OTStmt> lastlink;
-                for (lastlink = link; (lastlink = lastlink.Next) != null;) {
-
-                    // check for jump forloop that tells us where loop ends
-                    if (lastlink.Value is OTStmtJump) {
-                        OTStmtJump lastjump = (OTStmtJump) lastlink.Value;
-                        if (lastjump.label == looplabel) break;
-                    }
-
-                    // add to body block
-                    it.forbody.blkstmts.AddLast (lastlink.Value);
-                }
-
-                // make sure we found the 'jump forloop' where the for loop ends
-                if (lastlink == null) return false;
-
-                // remove all statements from caller's block including final jump
-                // but leave the loop label in place
-                for (LinkedListNode<OTStmt> nextlink = null; (nextlink = link.Next) != null;) {
-                    link.List.Remove (nextlink);
-                    if (nextlink == lastlink) break;
-                }
-
-                // if statement before loop label is an assignment, use it for the init statement
-                if (!iswhile && (link.Previous != null) && (link.Previous.Value is OTStmtStore)) {
-                    it.forinit = link.Previous.Value;
-                    link.List.Remove (link.Previous);
-                }
-
-                // if first statement of for body is 'if (...) jump breaklabel' use it for the test value
-                if ((it.forbody.blkstmts.First != null) && (it.forbody.blkstmts.First.Value is OTStmtCond)) {
-                    OTStmtCond condstmt = (OTStmtCond) it.forbody.blkstmts.First.Value;
-                    if ((condstmt.stmt is OTStmtJump) && (((OTStmtJump) condstmt.stmt).label.name == breakname + suffix)) {
-                        it.fortest = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
-                        it.forbody.blkstmts.RemoveFirst ();
-                    }
-                }
-
-                // if last statement of body is an assigment,
-                // use the assignment as the step statement
-                if (!iswhile && (it.forbody.blkstmts.Last != null) &&
-                        (it.forbody.blkstmts.Last.Value is OTStmtStore)) {
-                    LinkedListNode<OTStmt> storelink = it.forbody.blkstmts.Last;
-                    storelink.List.Remove (storelink);
-                    it.forstep = storelink.Value;
-                }
-
-                // finally replace the loop label with the whole for statement
-                link.Value = it;
-
-                // tell caller we made a change
-                return true;
-            }
-
-            public override void CountRefs ()
-            {
-                if (fortest != null) fortest.CountRefs (false);
-                if (forbody != null) forbody.CountRefs ();
-                if (forinit != null) forinit.CountRefs ();
-                if (forstep != null) forstep.CountRefs ();
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                return forbody.ReplaceOperand (oldopnd, newopnd) |
-                        ((forinit != null) && forinit.ReplaceOperand (oldopnd, newopnd)) |
-                        ((forstep != null) && forstep.ReplaceOperand (oldopnd, newopnd));
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return forbody.DetectDoForIfWhile (link) |
-                            ((forinit != null) && forinit.DetectDoForIfWhile (link)) |
-                            ((forstep != null) && forstep.DetectDoForIfWhile (link));
-            }
-
-            /**
-             * Assume we won't replace the for statement itself.
-             * But search all our sub-ordinate statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                forbody = (OTStmtBlock) forbody.ReplaceStatement (oldstmt, newstmt);
-                if (forinit != null) forinit = forinit.ReplaceStatement (oldstmt, newstmt);
-                if (forstep != null) forstep = forstep.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                if (iswhile) {
-                    twout.Write ("while (");
-                    if (fortest == null) {
-                        twout.Write ("TRUE");
-                    } else {
-                        twout.Write (StripBrtrue (fortest).PrintableString);
-                    }
-                } else {
-                    twout.Write ("for (");
-                    if (forinit != null) {
-                        forinit.PrintStmt (twout, indent + INDENT);
-                    } else {
-                        twout.Write (';');
-                    }
-                    if (fortest != null) {
-                        twout.Write (' ' + StripBrtrue (fortest).PrintableString);
-                    }
-                    twout.Write (';');
-                    if (forstep != null) {
-                        StringWriter sw = new StringWriter ();
-                        sw.Write (' ');
-                        forstep.PrintStmt (sw, indent + INDENT);
-                        StringBuilder sb = sw.GetStringBuilder ();
-                        int sl = sb.Length;
-                        if ((sl > 0) && (sb[sl-1] == ';')) sb.Remove (-- sl, 1);
-                        twout.Write (sb.ToString ());
-                    }
-                }
-
-                twout.Write (") ");
-                forbody.PrintStmt (twout, indent);
-            }
-        }
-
-        /**
-         * if/then/else block.
-         */
-        private class OTStmtIf : OTStmt {
-            private OTOpnd testvalu;
-            private OTStmt thenstmt;
-            private OTStmt elsestmt;  // might be null
-
-            /**
-             * Try to detect a structured if statement.
-             *
-             *   if (condition) jump ifdone_<suffix>;   << link points here
-             *      ... then body ...
-             * @ifdone_<suffix>;
-             *
-             *   if (condition) jump ifelse_<suffix>;
-             *      ... then body ...
-             *   jump ifdone_<suffix>;  << optional if true body doesn't fall through
-             * @ifelse_<suffix>;
-             *      ... else body ...
-             * @ifdone_<suffix>;
-             */
-            public static bool Detect (LinkedListNode<OTStmt> link)
-            {
-                OTStmtCond condstmt = (OTStmtCond) link.Value;
-                if (!(condstmt.stmt is OTStmtJump)) return false;
-
-                OTStmtJump jumpstmt = (OTStmtJump) condstmt.stmt;
-                if (jumpstmt.label.name.StartsWith (_ifDone)) {
-
-                    // then-only if
-
-                    // skip forward to find the ifdone_<suffix> label
-                    // also save the intervening statements for the then body
-                    OTStmtBlock thenbody;
-                    LinkedListNode<OTStmt> donelink = ScanForLabel (link, jumpstmt.label, out thenbody);
-
-                    // make sure we found matching label
-                    if (donelink == null) return false;
-
-                    // replace the jump ifdone_<suffix> with the <then body>
-                    OTStmtIf it = new OTStmtIf ();
-                    it.thenstmt = thenbody;
-
-                    // replace the test value with the opposite
-                    it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
-                    condstmt.valu = null;
-
-                    // strip out the true body statements from the main code including the ifdone_<suffix> label
-                    StripInterveningStatements (link, donelink);
-
-                    // replace the simple conditional with the if/then/else block
-                    link.Value = it;
-
-                    // tell caller we changed something
-                    return true;
-                }
-
-                if (jumpstmt.label.name.StartsWith (_ifElse)) {
-                    string suffix = jumpstmt.label.name.Substring (_ifElse.Length);
-
-                    // if/then/else
-                    OTStmtIf it = new OTStmtIf ();
-
-                    // skip forward to find the ifelse_<suffix> label
-                    // also save the intervening statements for the true body
-                    OTStmtBlock thenbody;
-                    LinkedListNode<OTStmt> elselink = ScanForLabel (link, jumpstmt.label, out thenbody);
-
-                    // make sure we found matching label
-                    if (elselink != null) {
-
-                        // the last statement of the then body might be a jump ifdone_<suffix>
-                        LinkedListNode<OTStmt> lastthenlink = thenbody.blkstmts.Last;
-                        if ((lastthenlink != null) && (lastthenlink.Value is OTStmtJump)) {
-                            OTStmtJump jumpifdone = (OTStmtJump) lastthenlink.Value;
-                            if (jumpifdone.label.name == _ifDone + suffix) {
-
-                                lastthenlink.List.Remove (lastthenlink);
-
-                                // skip forward to find the ifdone_<suffix> label
-                                // also save the intervening statements for the else body
-                                OTStmtBlock elsebody;
-                                LinkedListNode<OTStmt> donelink = ScanForLabel (elselink, jumpifdone.label, out elsebody);
-                                if (donelink != null) {
-
-                                    // replace the jump ifdone_<suffix> with the <true body>
-                                    it.thenstmt = thenbody;
-
-                                    // save the else body as well
-                                    it.elsestmt = elsebody;
-
-                                    // replace the test value with the opposite
-                                    it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
-                                    condstmt.valu = null;
-
-                                    // strip out the true and else body statements from the main code including the ifdone_<suffix> label
-                                    StripInterveningStatements (link, donelink);
-
-                                    // replace the simple conditional with the if/then/else block
-                                    link.Value = it;
-
-                                    // tell caller we changed something
-                                    return true;
-                                }
-                            }
-                        }
-
-                        // missing the jump _ifDone_<suffix>, so make it a simple if/then
-                        //   if (condition) jump ifelse_<suffix>;   << link
-                        //      ... then body ...                   << encapsulated in block thenbody
-                        // @ifelse_<suffix>;                        << elselink
-                        //      ... else body ...                   << still inline and leave it there
-                        // @ifdone_<suffix>;                        << strip this out
-
-                        // replace the jump ifelse_<suffix> with the <true body>
-                        it.thenstmt = thenbody;
-
-                        // replace the test value with the opposite
-                        it.testvalu = OTOpndUnOp.Make (MyOp.Brfalse, condstmt.valu);
-                        condstmt.valu = null;
-
-                        // strip out the then body statements from the main code including the ifelse_<suffix> label
-                        StripInterveningStatements (link, elselink);
-
-                        // there's a dangling unused ifdone_<suffix> label ahead that has to be stripped
-                        for (LinkedListNode<OTStmt> donelink = link; (donelink = donelink.Next) != null;) {
-                            if ((donelink.Value is OTStmtLabel) && (((OTStmtLabel) donelink.Value).label.name == _ifDone + suffix)) {
-                                donelink.List.Remove (donelink);
-                                break;
-                            }
-                        }
-
-                        // replace the simple conditional with the if/then/else block
-                        link.Value = it;
-
-                        // tell caller we changed something
-                        return true;
-                    }
-                }
-
-                return false;
-            }
-
-            private OTStmtIf () { }
-
-            public override void CountRefs ()
-            {
-                if (testvalu != null) testvalu.CountRefs (false);
-                if (thenstmt != null) thenstmt.CountRefs ();
-                if (elsestmt != null) elsestmt.CountRefs ();
-            }
-
-            public override bool ReplaceOperand (OTOpnd oldopnd, OTOpnd newopnd)
-            {
-                bool rc = thenstmt.ReplaceOperand (oldopnd, newopnd);
-                testvalu = testvalu.ReplaceOperand (oldopnd, newopnd, ref rc);
-                return rc;
-            }
-
-            public override bool DetectDoForIfWhile (LinkedListNode<OTStmt> link)
-            {
-                return ((thenstmt != null) && thenstmt.DetectDoForIfWhile (link)) |
-                       ((elsestmt != null) && elsestmt.DetectDoForIfWhile (link));
-            }
-
-            /**
-             * Assume we won't replace the if statement itself.
-             * But search all our sub-ordinate statements.
-             */
-            public override OTStmt ReplaceStatement (OTStmt oldstmt, OTStmt newstmt)
-            {
-                thenstmt = thenstmt.ReplaceStatement (oldstmt, newstmt);
-                if (elsestmt != null) elsestmt = elsestmt.ReplaceStatement (oldstmt, newstmt);
-                return this;
-            }
-
-            public override void PrintStmt (TextWriter twout, string indent)
-            {
-                twout.Write ("if (" + StripBrtrue (testvalu).PrintableString + ") ");
-                OTStmt thenst = ReduceStmtBody (thenstmt, false);
-                thenst.PrintStmt (twout, indent);
-                if (elsestmt != null) {
-                    twout.Write ('\n' + indent + "else ");
-                    OTStmt elsest = ReduceStmtBody (elsestmt, true);
-                    elsest.PrintStmt (twout, indent);
-                }
-            }
-
-            // strip block off a single jump so it prints inline instead of with braces around it
-            // also, if this is part of else, strip block for ifs to make else if statement
-            private static OTStmt ReduceStmtBody (OTStmt statement, bool stripif)
-            {
-                OTStmt onestmt = statement;
-                if ((onestmt is OTStmtBlock) && (((OTStmtBlock) onestmt).blkstmts.Count == 1)) {
-                    onestmt = ((OTStmtBlock) onestmt).blkstmts.First.Value;
-                    if ((onestmt is OTStmtJump) || (stripif && (onestmt is OTStmtIf))) {
-                        return onestmt;
-                    }
-                }
-                return statement;
-            }
-
-            /**
-             * Scan forward for a given label definition.
-             * Put intervening statements in a statement block.
-             * @param link = start scanning after this statement
-             * @param label = look for this label definition
-             * @param block = where to return intervening statement block
-             * @returns null: label definition not found
-             *          else: label definition statement
-             */
-            private static LinkedListNode<OTStmt> ScanForLabel (LinkedListNode<OTStmt> link,
-                        OTLabel label, out OTStmtBlock block)
-            {
-                block = new OTStmtBlock ();
-                while ((link = link.Next) != null) {
-                    if (link.Value is OTStmtLabel) {
-                        if (((OTStmtLabel) link.Value).label == label) break;
-                    }
-                    block.blkstmts.AddLast (link.Value);
-                }
-                return link;
-            }
-
-            /**
-             * Strip statements after link up to and including donelink.
-             */
-            private static void StripInterveningStatements (LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
-            {
-                LinkedListNode<OTStmt> striplink;
-                do {
-                    striplink = link.Next;
-                    striplink.List.Remove (striplink);
-                } while (striplink != donelink);
-            }
-        }
-
-        private class MyOp {
-            public int index;
-            public OpCode sysop;
-            public string name;
-            public string source;
-
-            private static Dictionary<string,MyOp> myopsbyname = new Dictionary<string,MyOp> ();
-            private static int nextindex = 0;
-
-            public MyOp (OpCode sysop)
-            {
-                this.index = nextindex ++;
-                this.sysop = sysop;
-                this.name  = sysop.Name;
-                myopsbyname.Add (name, this);
-            }
-
-            public MyOp (OpCode sysop, string source)
-            {
-                this.index  = nextindex ++;
-                this.sysop  = sysop;
-                this.name   = sysop.Name;
-                this.source = source;
-                myopsbyname.Add (name, this);
-            }
-
-            public MyOp (string name)
-            {
-                this.index = nextindex ++;
-                this.name  = name;
-                myopsbyname.Add (name, this);
-            }
-
-            public MyOp (string name, string source)
-            {
-                this.index  = nextindex ++;
-                this.name   = name;
-                this.source = source;
-                myopsbyname.Add (name, this);
-            }
-
-            public static MyOp GetByName (string name)
-            {
-                return myopsbyname[name];
-            }
-
-            public override string ToString ()
-            {
-                return name;
-            }
-
-            // these copied from OpCodes.cs
-            public static readonly MyOp Nop            = new MyOp (OpCodes.Nop);
-            public static readonly MyOp Break          = new MyOp (OpCodes.Break);
-            public static readonly MyOp Ldarg_0        = new MyOp (OpCodes.Ldarg_0);
-            public static readonly MyOp Ldarg_1        = new MyOp (OpCodes.Ldarg_1);
-            public static readonly MyOp Ldarg_2        = new MyOp (OpCodes.Ldarg_2);
-            public static readonly MyOp Ldarg_3        = new MyOp (OpCodes.Ldarg_3);
-            public static readonly MyOp Ldloc_0        = new MyOp (OpCodes.Ldloc_0);
-            public static readonly MyOp Ldloc_1        = new MyOp (OpCodes.Ldloc_1);
-            public static readonly MyOp Ldloc_2        = new MyOp (OpCodes.Ldloc_2);
-            public static readonly MyOp Ldloc_3        = new MyOp (OpCodes.Ldloc_3);
-            public static readonly MyOp Stloc_0        = new MyOp (OpCodes.Stloc_0);
-            public static readonly MyOp Stloc_1        = new MyOp (OpCodes.Stloc_1);
-            public static readonly MyOp Stloc_2        = new MyOp (OpCodes.Stloc_2);
-            public static readonly MyOp Stloc_3        = new MyOp (OpCodes.Stloc_3);
-            public static readonly MyOp Ldarg_S        = new MyOp (OpCodes.Ldarg_S);
-            public static readonly MyOp Ldarga_S       = new MyOp (OpCodes.Ldarga_S);
-            public static readonly MyOp Starg_S        = new MyOp (OpCodes.Starg_S);
-            public static readonly MyOp Ldloc_S        = new MyOp (OpCodes.Ldloc_S);
-            public static readonly MyOp Ldloca_S       = new MyOp (OpCodes.Ldloca_S);
-            public static readonly MyOp Stloc_S        = new MyOp (OpCodes.Stloc_S);
-            public static readonly MyOp Ldnull         = new MyOp (OpCodes.Ldnull);
-            public static readonly MyOp Ldc_I4_M1      = new MyOp (OpCodes.Ldc_I4_M1);
-            public static readonly MyOp Ldc_I4_0       = new MyOp (OpCodes.Ldc_I4_0);
-            public static readonly MyOp Ldc_I4_1       = new MyOp (OpCodes.Ldc_I4_1);
-            public static readonly MyOp Ldc_I4_2       = new MyOp (OpCodes.Ldc_I4_2);
-            public static readonly MyOp Ldc_I4_3       = new MyOp (OpCodes.Ldc_I4_3);
-            public static readonly MyOp Ldc_I4_4       = new MyOp (OpCodes.Ldc_I4_4);
-            public static readonly MyOp Ldc_I4_5       = new MyOp (OpCodes.Ldc_I4_5);
-            public static readonly MyOp Ldc_I4_6       = new MyOp (OpCodes.Ldc_I4_6);
-            public static readonly MyOp Ldc_I4_7       = new MyOp (OpCodes.Ldc_I4_7);
-            public static readonly MyOp Ldc_I4_8       = new MyOp (OpCodes.Ldc_I4_8);
-            public static readonly MyOp Ldc_I4_S       = new MyOp (OpCodes.Ldc_I4_S);
-            public static readonly MyOp Ldc_I4         = new MyOp (OpCodes.Ldc_I4);
-            public static readonly MyOp Ldc_I8         = new MyOp (OpCodes.Ldc_I8);
-            public static readonly MyOp Ldc_R4         = new MyOp (OpCodes.Ldc_R4);
-            public static readonly MyOp Ldc_R8         = new MyOp (OpCodes.Ldc_R8);
-            public static readonly MyOp Dup            = new MyOp (OpCodes.Dup);
-            public static readonly MyOp Pop            = new MyOp (OpCodes.Pop);
-            public static readonly MyOp Jmp            = new MyOp (OpCodes.Jmp);
-            public static readonly MyOp Call           = new MyOp (OpCodes.Call);
-            public static readonly MyOp Calli          = new MyOp (OpCodes.Calli);
-            public static readonly MyOp Ret            = new MyOp (OpCodes.Ret);
-            public static readonly MyOp Br_S           = new MyOp (OpCodes.Br_S);
-            public static readonly MyOp Brfalse_S      = new MyOp (OpCodes.Brfalse_S);
-            public static readonly MyOp Brtrue_S       = new MyOp (OpCodes.Brtrue_S);
-            public static readonly MyOp Beq_S          = new MyOp (OpCodes.Beq_S, "==");
-            public static readonly MyOp Bge_S          = new MyOp (OpCodes.Bge_S, ">=");
-            public static readonly MyOp Bgt_S          = new MyOp (OpCodes.Bgt_S, ">");
-            public static readonly MyOp Ble_S          = new MyOp (OpCodes.Ble_S, "<=");
-            public static readonly MyOp Blt_S          = new MyOp (OpCodes.Blt_S, "<");
-            public static readonly MyOp Bne_Un_S       = new MyOp (OpCodes.Bne_Un_S, "!=");
-            public static readonly MyOp Bge_Un_S       = new MyOp (OpCodes.Bge_Un_S);
-            public static readonly MyOp Bgt_Un_S       = new MyOp (OpCodes.Bgt_Un_S);
-            public static readonly MyOp Ble_Un_S       = new MyOp (OpCodes.Ble_Un_S);
-            public static readonly MyOp Blt_Un_S       = new MyOp (OpCodes.Blt_Un_S);
-            public static readonly MyOp Br             = new MyOp (OpCodes.Br);
-            public static readonly MyOp Brfalse        = new MyOp (OpCodes.Brfalse, "!");
-            public static readonly MyOp Brtrue         = new MyOp (OpCodes.Brtrue,  "!!");
-            public static readonly MyOp Beq            = new MyOp (OpCodes.Beq, "==");
-            public static readonly MyOp Bge            = new MyOp (OpCodes.Bge, ">=");
-            public static readonly MyOp Bgt            = new MyOp (OpCodes.Bgt, ">");
-            public static readonly MyOp Ble            = new MyOp (OpCodes.Ble, "<=");
-            public static readonly MyOp Blt            = new MyOp (OpCodes.Blt, "<");
-            public static readonly MyOp Bne_Un         = new MyOp (OpCodes.Bne_Un, "!=");
-            public static readonly MyOp Bge_Un         = new MyOp (OpCodes.Bge_Un);
-            public static readonly MyOp Bgt_Un         = new MyOp (OpCodes.Bgt_Un);
-            public static readonly MyOp Ble_Un         = new MyOp (OpCodes.Ble_Un);
-            public static readonly MyOp Blt_Un         = new MyOp (OpCodes.Blt_Un);
-            public static readonly MyOp Switch         = new MyOp (OpCodes.Switch);
-            public static readonly MyOp Ldind_I1       = new MyOp (OpCodes.Ldind_I1);
-            public static readonly MyOp Ldind_U1       = new MyOp (OpCodes.Ldind_U1);
-            public static readonly MyOp Ldind_I2       = new MyOp (OpCodes.Ldind_I2);
-            public static readonly MyOp Ldind_U2       = new MyOp (OpCodes.Ldind_U2);
-            public static readonly MyOp Ldind_I4       = new MyOp (OpCodes.Ldind_I4);
-            public static readonly MyOp Ldind_U4       = new MyOp (OpCodes.Ldind_U4);
-            public static readonly MyOp Ldind_I8       = new MyOp (OpCodes.Ldind_I8);
-            public static readonly MyOp Ldind_I        = new MyOp (OpCodes.Ldind_I);
-            public static readonly MyOp Ldind_R4       = new MyOp (OpCodes.Ldind_R4);
-            public static readonly MyOp Ldind_R8       = new MyOp (OpCodes.Ldind_R8);
-            public static readonly MyOp Ldind_Ref      = new MyOp (OpCodes.Ldind_Ref);
-            public static readonly MyOp Stind_Ref      = new MyOp (OpCodes.Stind_Ref);
-            public static readonly MyOp Stind_I1       = new MyOp (OpCodes.Stind_I1);
-            public static readonly MyOp Stind_I2       = new MyOp (OpCodes.Stind_I2);
-            public static readonly MyOp Stind_I4       = new MyOp (OpCodes.Stind_I4);
-            public static readonly MyOp Stind_I8       = new MyOp (OpCodes.Stind_I8);
-            public static readonly MyOp Stind_R4       = new MyOp (OpCodes.Stind_R4);
-            public static readonly MyOp Stind_R8       = new MyOp (OpCodes.Stind_R8);
-            public static readonly MyOp Add            = new MyOp (OpCodes.Add, "+");
-            public static readonly MyOp Sub            = new MyOp (OpCodes.Sub, "-");
-            public static readonly MyOp Mul            = new MyOp (OpCodes.Mul, "*");
-            public static readonly MyOp Div            = new MyOp (OpCodes.Div, "/");
-            public static readonly MyOp Div_Un         = new MyOp (OpCodes.Div_Un);
-            public static readonly MyOp Rem            = new MyOp (OpCodes.Rem, "%");
-            public static readonly MyOp Rem_Un         = new MyOp (OpCodes.Rem_Un);
-            public static readonly MyOp And            = new MyOp (OpCodes.And, "&");
-            public static readonly MyOp Or             = new MyOp (OpCodes.Or, "|");
-            public static readonly MyOp Xor            = new MyOp (OpCodes.Xor, "^");
-            public static readonly MyOp Shl            = new MyOp (OpCodes.Shl, "<<");
-            public static readonly MyOp Shr            = new MyOp (OpCodes.Shr, ">>");
-            public static readonly MyOp Shr_Un         = new MyOp (OpCodes.Shr_Un);
-            public static readonly MyOp Neg            = new MyOp (OpCodes.Neg, "-");
-            public static readonly MyOp Not            = new MyOp (OpCodes.Not, "~");
-            public static readonly MyOp Conv_I1        = new MyOp (OpCodes.Conv_I1);
-            public static readonly MyOp Conv_I2        = new MyOp (OpCodes.Conv_I2);
-            public static readonly MyOp Conv_I4        = new MyOp (OpCodes.Conv_I4);
-            public static readonly MyOp Conv_I8        = new MyOp (OpCodes.Conv_I8);
-            public static readonly MyOp Conv_R4        = new MyOp (OpCodes.Conv_R4);
-            public static readonly MyOp Conv_R8        = new MyOp (OpCodes.Conv_R8);
-            public static readonly MyOp Conv_U4        = new MyOp (OpCodes.Conv_U4);
-            public static readonly MyOp Conv_U8        = new MyOp (OpCodes.Conv_U8);
-            public static readonly MyOp Callvirt       = new MyOp (OpCodes.Callvirt);
-            public static readonly MyOp Cpobj          = new MyOp (OpCodes.Cpobj);
-            public static readonly MyOp Ldobj          = new MyOp (OpCodes.Ldobj);
-            public static readonly MyOp Ldstr          = new MyOp (OpCodes.Ldstr);
-            public static readonly MyOp Newobj         = new MyOp (OpCodes.Newobj);
-            public static readonly MyOp Castclass      = new MyOp (OpCodes.Castclass);
-            public static readonly MyOp Isinst         = new MyOp (OpCodes.Isinst);
-            public static readonly MyOp Conv_R_Un      = new MyOp (OpCodes.Conv_R_Un);
-            public static readonly MyOp Unbox          = new MyOp (OpCodes.Unbox);
-            public static readonly MyOp Throw          = new MyOp (OpCodes.Throw);
-            public static readonly MyOp Ldfld          = new MyOp (OpCodes.Ldfld);
-            public static readonly MyOp Ldflda         = new MyOp (OpCodes.Ldflda);
-            public static readonly MyOp Stfld          = new MyOp (OpCodes.Stfld);
-            public static readonly MyOp Ldsfld         = new MyOp (OpCodes.Ldsfld);
-            public static readonly MyOp Ldsflda        = new MyOp (OpCodes.Ldsflda);
-            public static readonly MyOp Stsfld         = new MyOp (OpCodes.Stsfld);
-            public static readonly MyOp Stobj          = new MyOp (OpCodes.Stobj);
-            public static readonly MyOp Conv_Ovf_I1_Un = new MyOp (OpCodes.Conv_Ovf_I1_Un);
-            public static readonly MyOp Conv_Ovf_I2_Un = new MyOp (OpCodes.Conv_Ovf_I2_Un);
-            public static readonly MyOp Conv_Ovf_I4_Un = new MyOp (OpCodes.Conv_Ovf_I4_Un);
-            public static readonly MyOp Conv_Ovf_I8_Un = new MyOp (OpCodes.Conv_Ovf_I8_Un);
-            public static readonly MyOp Conv_Ovf_U1_Un = new MyOp (OpCodes.Conv_Ovf_U1_Un);
-            public static readonly MyOp Conv_Ovf_U2_Un = new MyOp (OpCodes.Conv_Ovf_U2_Un);
-            public static readonly MyOp Conv_Ovf_U4_Un = new MyOp (OpCodes.Conv_Ovf_U4_Un);
-            public static readonly MyOp Conv_Ovf_U8_Un = new MyOp (OpCodes.Conv_Ovf_U8_Un);
-            public static readonly MyOp Conv_Ovf_I_Un  = new MyOp (OpCodes.Conv_Ovf_I_Un);
-            public static readonly MyOp Conv_Ovf_U_Un  = new MyOp (OpCodes.Conv_Ovf_U_Un);
-            public static readonly MyOp Box            = new MyOp (OpCodes.Box);
-            public static readonly MyOp Newarr         = new MyOp (OpCodes.Newarr);
-            public static readonly MyOp Ldlen          = new MyOp (OpCodes.Ldlen);
-            public static readonly MyOp Ldelema        = new MyOp (OpCodes.Ldelema);
-            public static readonly MyOp Ldelem_I1      = new MyOp (OpCodes.Ldelem_I1);
-            public static readonly MyOp Ldelem_U1      = new MyOp (OpCodes.Ldelem_U1);
-            public static readonly MyOp Ldelem_I2      = new MyOp (OpCodes.Ldelem_I2);
-            public static readonly MyOp Ldelem_U2      = new MyOp (OpCodes.Ldelem_U2);
-            public static readonly MyOp Ldelem_I4      = new MyOp (OpCodes.Ldelem_I4);
-            public static readonly MyOp Ldelem_U4      = new MyOp (OpCodes.Ldelem_U4);
-            public static readonly MyOp Ldelem_I8      = new MyOp (OpCodes.Ldelem_I8);
-            public static readonly MyOp Ldelem_I       = new MyOp (OpCodes.Ldelem_I);
-            public static readonly MyOp Ldelem_R4      = new MyOp (OpCodes.Ldelem_R4);
-            public static readonly MyOp Ldelem_R8      = new MyOp (OpCodes.Ldelem_R8);
-            public static readonly MyOp Ldelem_Ref     = new MyOp (OpCodes.Ldelem_Ref);
-            public static readonly MyOp Stelem_I       = new MyOp (OpCodes.Stelem_I);
-            public static readonly MyOp Stelem_I1      = new MyOp (OpCodes.Stelem_I1);
-            public static readonly MyOp Stelem_I2      = new MyOp (OpCodes.Stelem_I2);
-            public static readonly MyOp Stelem_I4      = new MyOp (OpCodes.Stelem_I4);
-            public static readonly MyOp Stelem_I8      = new MyOp (OpCodes.Stelem_I8);
-            public static readonly MyOp Stelem_R4      = new MyOp (OpCodes.Stelem_R4);
-            public static readonly MyOp Stelem_R8      = new MyOp (OpCodes.Stelem_R8);
-            public static readonly MyOp Stelem_Ref     = new MyOp (OpCodes.Stelem_Ref);
-            public static readonly MyOp Ldelem         = new MyOp (OpCodes.Ldelem);
-            public static readonly MyOp Stelem         = new MyOp (OpCodes.Stelem);
-            public static readonly MyOp Unbox_Any      = new MyOp (OpCodes.Unbox_Any);
-            public static readonly MyOp Conv_Ovf_I1    = new MyOp (OpCodes.Conv_Ovf_I1);
-            public static readonly MyOp Conv_Ovf_U1    = new MyOp (OpCodes.Conv_Ovf_U1);
-            public static readonly MyOp Conv_Ovf_I2    = new MyOp (OpCodes.Conv_Ovf_I2);
-            public static readonly MyOp Conv_Ovf_U2    = new MyOp (OpCodes.Conv_Ovf_U2);
-            public static readonly MyOp Conv_Ovf_I4    = new MyOp (OpCodes.Conv_Ovf_I4);
-            public static readonly MyOp Conv_Ovf_U4    = new MyOp (OpCodes.Conv_Ovf_U4);
-            public static readonly MyOp Conv_Ovf_I8    = new MyOp (OpCodes.Conv_Ovf_I8);
-            public static readonly MyOp Conv_Ovf_U8    = new MyOp (OpCodes.Conv_Ovf_U8);
-            public static readonly MyOp Refanyval      = new MyOp (OpCodes.Refanyval);
-            public static readonly MyOp Ckfinite       = new MyOp (OpCodes.Ckfinite);
-            public static readonly MyOp Mkrefany       = new MyOp (OpCodes.Mkrefany);
-            public static readonly MyOp Ldtoken        = new MyOp (OpCodes.Ldtoken);
-            public static readonly MyOp Conv_U2        = new MyOp (OpCodes.Conv_U2);
-            public static readonly MyOp Conv_U1        = new MyOp (OpCodes.Conv_U1);
-            public static readonly MyOp Conv_I         = new MyOp (OpCodes.Conv_I);
-            public static readonly MyOp Conv_Ovf_I     = new MyOp (OpCodes.Conv_Ovf_I);
-            public static readonly MyOp Conv_Ovf_U     = new MyOp (OpCodes.Conv_Ovf_U);
-            public static readonly MyOp Add_Ovf        = new MyOp (OpCodes.Add_Ovf);
-            public static readonly MyOp Add_Ovf_Un     = new MyOp (OpCodes.Add_Ovf_Un);
-            public static readonly MyOp Mul_Ovf        = new MyOp (OpCodes.Mul_Ovf);
-            public static readonly MyOp Mul_Ovf_Un     = new MyOp (OpCodes.Mul_Ovf_Un);
-            public static readonly MyOp Sub_Ovf        = new MyOp (OpCodes.Sub_Ovf);
-            public static readonly MyOp Sub_Ovf_Un     = new MyOp (OpCodes.Sub_Ovf_Un);
-            public static readonly MyOp Endfinally     = new MyOp (OpCodes.Endfinally);
-            public static readonly MyOp Leave          = new MyOp (OpCodes.Leave);
-            public static readonly MyOp Leave_S        = new MyOp (OpCodes.Leave_S);
-            public static readonly MyOp Stind_I        = new MyOp (OpCodes.Stind_I);
-            public static readonly MyOp Conv_U         = new MyOp (OpCodes.Conv_U);
-            public static readonly MyOp Prefix7        = new MyOp (OpCodes.Prefix7);
-            public static readonly MyOp Prefix6        = new MyOp (OpCodes.Prefix6);
-            public static readonly MyOp Prefix5        = new MyOp (OpCodes.Prefix5);
-            public static readonly MyOp Prefix4        = new MyOp (OpCodes.Prefix4);
-            public static readonly MyOp Prefix3        = new MyOp (OpCodes.Prefix3);
-            public static readonly MyOp Prefix2        = new MyOp (OpCodes.Prefix2);
-            public static readonly MyOp Prefix1        = new MyOp (OpCodes.Prefix1);
-            public static readonly MyOp Prefixref      = new MyOp (OpCodes.Prefixref);
-            public static readonly MyOp Arglist        = new MyOp (OpCodes.Arglist);
-            public static readonly MyOp Ceq            = new MyOp (OpCodes.Ceq, "==");
-            public static readonly MyOp Cgt            = new MyOp (OpCodes.Cgt, ">");
-            public static readonly MyOp Cgt_Un         = new MyOp (OpCodes.Cgt_Un);
-            public static readonly MyOp Clt            = new MyOp (OpCodes.Clt, "<");
-            public static readonly MyOp Clt_Un         = new MyOp (OpCodes.Clt_Un);
-            public static readonly MyOp Ldftn          = new MyOp (OpCodes.Ldftn);
-            public static readonly MyOp Ldvirtftn      = new MyOp (OpCodes.Ldvirtftn);
-            public static readonly MyOp Ldarg          = new MyOp (OpCodes.Ldarg);
-            public static readonly MyOp Ldarga         = new MyOp (OpCodes.Ldarga);
-            public static readonly MyOp Starg          = new MyOp (OpCodes.Starg);
-            public static readonly MyOp Ldloc          = new MyOp (OpCodes.Ldloc);
-            public static readonly MyOp Ldloca         = new MyOp (OpCodes.Ldloca);
-            public static readonly MyOp Stloc          = new MyOp (OpCodes.Stloc);
-            public static readonly MyOp Localloc       = new MyOp (OpCodes.Localloc);
-            public static readonly MyOp Endfilter      = new MyOp (OpCodes.Endfilter);
-            public static readonly MyOp Unaligned      = new MyOp (OpCodes.Unaligned);
-            public static readonly MyOp Volatile       = new MyOp (OpCodes.Volatile);
-            public static readonly MyOp Tailcall       = new MyOp (OpCodes.Tailcall);
-            public static readonly MyOp Initobj        = new MyOp (OpCodes.Initobj);
-            public static readonly MyOp Constrained    = new MyOp (OpCodes.Constrained);
-            public static readonly MyOp Cpblk          = new MyOp (OpCodes.Cpblk);
-            public static readonly MyOp Initblk        = new MyOp (OpCodes.Initblk);
-            public static readonly MyOp Rethrow        = new MyOp (OpCodes.Rethrow);
-            public static readonly MyOp Sizeof         = new MyOp (OpCodes.Sizeof);
-            public static readonly MyOp Refanytype     = new MyOp (OpCodes.Refanytype);
-            public static readonly MyOp Readonly       = new MyOp (OpCodes.Readonly);
-
-            // used internally
-            public static readonly MyOp Cge            = new MyOp ("cge", ">=");
-            public static readonly MyOp Cle            = new MyOp ("cle", "<=");
-            public static readonly MyOp Cne            = new MyOp ("cne", "!=");
-        }
-    }
-}

+ 0 - 102
OpenSim/Region/ScriptEngine/XMREngine/XMRScriptThread.cs

@@ -1,102 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using OpenSim.Framework.Monitoring;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-    /**
-     * @brief There are NUMSCRIPTHREADWKRS of these.
-     *        Each sits in a loop checking the Start and Yield queues for 
-     *        a script to run and calls the script as a microthread.
-     */
-    public class XMRScriptThread
-    {
-        public bool         m_WakeUpThis = false;
-        public  DateTime    m_LastRanAt = DateTime.MinValue;
-        public  int         m_ScriptThreadTID = 0;
-        public  long        m_ScriptExecTime = 0;
-        private Thread      thd;
-        private XMREngine   engine;
-        public  XMRInstance m_RunInstance = null;
-
-        public XMRScriptThread(XMREngine eng, int i)
-        {
-            engine = eng;
-            if(i < 0)
-                thd = XMREngine.StartMyThread(RunScriptThread, "xmrengine script", ThreadPriority.Normal);
-            else
-                thd = XMREngine.StartMyThread(RunScriptThread, "xmrengineExec" + i.ToString(), ThreadPriority.Normal);
-            engine.AddThread(thd, this);
-            m_ScriptThreadTID = thd.ManagedThreadId;
-        }
-
-        public void Terminate()
-        {
-            m_WakeUpThis = true;
-            if(!thd.Join(250))
-                thd.Abort();
-
-            engine.RemoveThread(thd);
-
-            thd = null;
-        }
- 
-        /**
-         * @brief Wake up this XMRScriptThread instance.
-         */
-        public void WakeUpScriptThread()
-        {
-                m_WakeUpThis = true;
-        }
-
-        /**
-         * @brief A script instance was just removed from the Start or Yield Queue.
-         *        So run it for a little bit then stick in whatever queue it should go in.
-         */
-
-        private void RunScriptThread()
-        {
-            engine.RunScriptThread(this);
-        }
-
-        public void RunInstance (XMRInstance inst)
-        {
-            m_LastRanAt = DateTime.UtcNow;
-            m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds;
-            inst.m_IState = XMRInstState.RUNNING;
-            m_RunInstance = inst;
-            XMRInstState newIState = inst.RunOne();
-            m_RunInstance = null;
-            engine.HandleNewIState(inst, newIState);
-            m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
-        }
-    }
-}

+ 0 - 196
OpenSim/Region/ScriptEngine/XMREngine/XMRScriptUThread.cs

@@ -1,196 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the OpenSimulator Project nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-
-/***************************\
- *  Use standard C# code   *
- *  - uses stack smashing  *
-\***************************/
-
-namespace OpenSim.Region.ScriptEngine.XMREngine
-{
-
-    public class ScriptUThread_Nul : IScriptUThread, IDisposable
-    {
-        private int active;     // -1: hibernating
-                                //  0: exited
-                                //  1: running
-        private XMRInstance instance;
-
-        public ScriptUThread_Nul (XMRInstance instance)
-        {
-            this.instance = instance;
-        }
-
-        /**
-         * @brief Start script event handler from the beginning.
-         *        Return when either the script event handler completes
-         *        or the script calls Hiber().
-         * @returns null: script did not throw any exception so far
-         *          else: script threw an exception
-         */
-        public Exception StartEx ()
-        {
-             // We should only be called when no event handler running.
-            if (active != 0)
-                throw new Exception ("active=" + active);
-
-             // Start script event handler from very beginning.
-            active = 1;
-            Exception except = null;
-            instance.callMode = XMRInstance.CallMode_NORMAL;
-            try
-            {
-                instance.CallSEH ();        // run script event handler
-                active = 0;
-            }
-            catch (StackHibernateException)
-            {
-                if (instance.callMode != XMRInstance.CallMode_SAVE)
-                {
-                    throw new Exception ("callMode=" + instance.callMode);
-                }
-                active = -1;                // it is hibernating, can be resumed
-            }
-            catch (Exception e)
-            {
-                active = 0;
-                except = e;                 // threw exception, save for Start()/Resume()
-            }
-
-             // Return whether or not script threw an exception.
-            return except;
-        }
-
-        /**
-         * @brief We now want to run some more script code from where it last hibernated
-         *        until it either finishes the script event handler or until the script
-         *        calls Hiber() again.
-         */
-        public Exception ResumeEx ()
-        {
-             // We should only be called when script is hibernating.
-            if (active >= 0)
-                throw new Exception ("active=" + active);
-
-             // Resume script from captured stack.
-            instance.callMode = XMRInstance.CallMode_RESTORE;
-            instance.suspendOnCheckRunTemp = true;
-            Exception except = null;
-            try
-            {
-                instance.CallSEH ();        // run script event handler
-                active = 0;
-            }
-            catch (StackHibernateException)
-            {
-                if (instance.callMode != XMRInstance.CallMode_SAVE)
-                {
-                    throw new Exception ("callMode=" + instance.callMode);
-                }
-                active = -1;
-            }
-            catch (Exception e)
-            {
-                active = 0;
-                except = e;                 // threw exception, save for Start()/Resume()
-            }
-
-             // Return whether or not script threw an exception.
-            return except;
-        }
-
-        /**
-         * @brief Script is being closed out.
-         *        Terminate thread asap.
-         */
-        public void Dispose ()
-        { }
-
-        /**
-         * @brief Determine if script is active.
-         * Returns: 0: nothing started or has returned
-         *             Resume() must not be called
-         *             Start() may be called
-         *             Hiber() must not be called
-         *         -1: thread has called Hiber()
-         *             Resume() may be called
-         *             Start() may be called
-         *             Hiber() must not be called
-         *          1: thread is running
-         *             Resume() must not be called
-         *             Start() must not be called
-         *             Hiber() may be called
-         */
-        public int Active ()
-        {
-            return active;
-        }
-
-        /**
-         * @brief Called by the script event handler whenever it wants to hibernate.
-         */
-        public void Hiber ()
-        {
-            if (instance.callMode != XMRInstance.CallMode_NORMAL) {
-                throw new Exception ("callMode=" + instance.callMode);
-            }
-
-            switch (active) {
-
-                // the stack has been restored as a result of calling ResumeEx()
-                // say the microthread is now active and resume processing
-                case -1: {
-                    active = 1;
-                    return;
-                }
-
-                // the script event handler wants to hibernate
-                // capture stack frames and unwind to Start() or Resume()
-                case 1: {
-                    instance.callMode = XMRInstance.CallMode_SAVE;
-                    instance.stackFrames = null;
-                    throw new StackHibernateException ();
-                }
-
-                default: throw new Exception ("active=" + active);
-            }
-        }
-
-        /**
-         * @brief Number of remaining stack bytes.
-         */
-        public int StackLeft ()
-        {
-            return 0x7FFFFFFF;
-        }
-
-        public class StackHibernateException : Exception, IXMRUncatchable { }
-    }
-}
-

+ 35 - 24
OpenSim/Region/ScriptEngine/XMREngine/MMRDelegateCommon.cs → OpenSim/Region/ScriptEngine/YEngine/MMRDelegateCommon.cs

@@ -30,65 +30,76 @@ using System.Collections.Generic;
 using System.Reflection;
 using System.Reflection.Emit;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine {
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
 
-    public class DelegateCommon {
+    public class DelegateCommon
+    {
         private string sig;  // rettype(arg1type,arg2type,...), eg, "void(list,string,integer)"
         private Type type;   // resultant delegate type
 
-        private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon> ();
-        private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon> ();
+        private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon>();
+        private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon>();
         private static ModuleBuilder delegateModuleBuilder = null;
-        public  static Type[] constructorArgTypes = new Type[] { typeof (object), typeof (IntPtr) };
+        public static Type[] constructorArgTypes = new Type[] { typeof(object), typeof(IntPtr) };
 
-        private DelegateCommon () { }
+        private DelegateCommon()
+        {
+        }
 
-        public static Type GetType (System.Type ret, System.Type[] args, string sig)
+        public static Type GetType(System.Type ret, System.Type[] args, string sig)
         {
             DelegateCommon dc;
-            lock (delegateCommons) {
-                if (!delegateCommons.TryGetValue (sig, out dc)) {
-                    dc = new DelegateCommon ();
-                    dc.sig  = sig;
-                    dc.type = CreateDelegateType (sig, ret, args);
-                    delegateCommons.Add (sig, dc);
-                    delegateCommonsBySysType.Add (dc.type, dc);
+            lock(delegateCommons)
+            {
+                if(!delegateCommons.TryGetValue(sig, out dc))
+                {
+                    dc = new DelegateCommon();
+                    dc.sig = sig;
+                    dc.type = CreateDelegateType(sig, ret, args);
+                    delegateCommons.Add(sig, dc);
+                    delegateCommonsBySysType.Add(dc.type, dc);
                 }
             }
             return dc.type;
         }
 
-        public static Type TryGetType (string sig)
+        public static Type TryGetType(string sig)
         {
             DelegateCommon dc;
-            lock (delegateCommons) {
-                if (!delegateCommons.TryGetValue (sig, out dc)) dc = null;
+            lock(delegateCommons)
+            {
+                if(!delegateCommons.TryGetValue(sig, out dc))
+                    dc = null;
             }
             return (dc == null) ? null : dc.type;
         }
 
-        public static string TryGetName (Type t)
+        public static string TryGetName(Type t)
         {
             DelegateCommon dc;
-            lock (delegateCommons) {
-                if (!delegateCommonsBySysType.TryGetValue (t, out dc)) dc = null;
+            lock(delegateCommons)
+            {
+                if(!delegateCommonsBySysType.TryGetValue(t, out dc))
+                    dc = null;
             }
             return (dc == null) ? null : dc.sig;
         }
 
         // http://blog.bittercoder.com/PermaLink,guid,a770377a-b1ad-4590-9145-36381757a52b.aspx
-        private static Type CreateDelegateType (string name, Type retType, Type[] argTypes)
+        private static Type CreateDelegateType(string name, Type retType, Type[] argTypes)
         {
-            if (delegateModuleBuilder == null) {
+            if(delegateModuleBuilder == null)
+            {
                 AssemblyName assembly = new AssemblyName();
                 assembly.Name = "CustomDelegateAssembly";
                 AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
                 delegateModuleBuilder = assemblyBuilder.DefineDynamicModule("CustomDelegateModule");
             }
 
-            TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name, 
+            TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name,
                 TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class |
-                TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof (MulticastDelegate));
+                TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(MulticastDelegate));
 
             ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
                 MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public,

+ 37 - 36
OpenSim/Region/ScriptEngine/XMREngine/MMRIEventHandlers.cs → OpenSim/Region/ScriptEngine/YEngine/MMRIEventHandlers.cs

@@ -33,43 +33,44 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
-    public interface IEventHandlers {
-        void at_rot_target (int tnum, LSL_Rotation targetrot, LSL_Rotation ourrot);
-        void at_target (int tnum, LSL_Vector targetpos, LSL_Vector ourpos);
-        void attach (string id);
-        void changed (int change);
-        void collision (int num_detected);
-        void collision_end (int num_detected);
-        void collision_start (int num_detected);
-        void control (string id, int held, int change);
-        void dataserver (string queryid, string data);
-        void email (string time, string address, string subj, string message, int num_left);
-        void http_request (string request_id, string method, string body);
-        void http_response (string request_id, int status, LSL_List metadata, string body);
-        void land_collision (LSL_Vector pos);
-        void land_collision_end (LSL_Vector pos);
-        void land_collision_start (LSL_Vector pos);
-        void link_message (int sender_num, int num, string str, string id);
-        void listen (int channel, string name, string id, string message);
-        void money (string id, int amount);
-        void moving_end ();
-        void moving_start ();
-        void no_sensor ();
-        void not_at_rot_target ();
-        void not_at_target ();
-        void object_rez (string id);
-        void on_rez (int start_param);
-        void remote_data (int event_type, string channel, string message_id, string sender, int idata, string sdata);
-        void run_time_permissions (int perm);
-        void sensor (int num_detected);
-        void state_entry ();
-        void state_exit ();
-        void timer ();
-        void touch (int num_detected);
-        void touch_start (int num_detected);
-        void touch_end (int num_detected);
+    public interface IEventHandlers
+    {
+        void at_rot_target(int tnum, LSL_Rotation targetrot, LSL_Rotation ourrot);
+        void at_target(int tnum, LSL_Vector targetpos, LSL_Vector ourpos);
+        void attach(string id);
+        void changed(int change);
+        void collision(int num_detected);
+        void collision_end(int num_detected);
+        void collision_start(int num_detected);
+        void control(string id, int held, int change);
+        void dataserver(string queryid, string data);
+        void email(string time, string address, string subj, string message, int num_left);
+        void http_request(string request_id, string method, string body);
+        void http_response(string request_id, int status, LSL_List metadata, string body);
+        void land_collision(LSL_Vector pos);
+        void land_collision_end(LSL_Vector pos);
+        void land_collision_start(LSL_Vector pos);
+        void link_message(int sender_num, int num, string str, string id);
+        void listen(int channel, string name, string id, string message);
+        void money(string id, int amount);
+        void moving_end();
+        void moving_start();
+        void no_sensor();
+        void not_at_rot_target();
+        void not_at_target();
+        void object_rez(string id);
+        void on_rez(int start_param);
+        void remote_data(int event_type, string channel, string message_id, string sender, int idata, string sdata);
+        void run_time_permissions(int perm);
+        void sensor(int num_detected);
+        void state_entry();
+        void state_exit();
+        void timer();
+        void touch(int num_detected);
+        void touch_start(int num_detected);
+        void touch_end(int num_detected);
         void transaction_result(string id, int success, string data);
         void path_update(int type, LSL_List data);
         void region_cross(LSL_Vector newpos, LSL_Vector oldpos);

+ 33 - 24
OpenSim/Region/ScriptEngine/XMREngine/MMRInternalFuncDict.cs → OpenSim/Region/ScriptEngine/YEngine/MMRInternalFuncDict.cs

@@ -30,9 +30,11 @@ using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine {
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
 
-    public class InternalFuncDict : VarDict {
+    public class InternalFuncDict: VarDict
+    {
 
         /**
          * @brief build dictionary of internal functions from an interface.
@@ -41,50 +43,57 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
          *                 false: catalog by simple name only, eg, state_entry
          * @returns dictionary of function definition tokens
          */
-        public InternalFuncDict (Type iface, bool inclSig)
-            : base (false)
+        public InternalFuncDict(Type iface, bool inclSig)
+            : base(false)
         {
             /*
              * Loop through list of all methods declared in the interface.
              */
-            System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods ();
-            foreach (System.Reflection.MethodInfo ifaceMethod in ifaceMethods) {
+            System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods();
+            foreach(System.Reflection.MethodInfo ifaceMethod in ifaceMethods)
+            {
                 string key = ifaceMethod.Name;
 
                 /*
                  * Only do ones that begin with lower-case letters...
                  * as any others can't be referenced by scripts
                  */
-                if ((key[0] < 'a') || (key[0] > 'z')) continue;
+                if((key[0] < 'a') || (key[0] > 'z'))
+                    continue;
 
-                try {
+                try
+                {
 
                     /*
                      * Create a corresponding TokenDeclVar struct.
                      */
-                    System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters ();
-                    TokenArgDecl argDecl = new TokenArgDecl (null);
-                    for (int i = 0; i < parameters.Length; i++) {
+                    System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters();
+                    TokenArgDecl argDecl = new TokenArgDecl(null);
+                    for(int i = 0; i < parameters.Length; i++)
+                    {
                         System.Reflection.ParameterInfo param = parameters[i];
-                        TokenType type = TokenType.FromSysType (null, param.ParameterType);
-                        TokenName name = new TokenName (null, param.Name);
-                        argDecl.AddArg (type, name);
+                        TokenType type = TokenType.FromSysType(null, param.ParameterType);
+                        TokenName name = new TokenName(null, param.Name);
+                        argDecl.AddArg(type, name);
                     }
-                    TokenDeclVar declFunc = new TokenDeclVar (null, null, null);
-                    declFunc.name         = new TokenName (null, key);
-                    declFunc.retType      = TokenType.FromSysType (null, ifaceMethod.ReturnType);
-                    declFunc.argDecl      = argDecl;
+                    TokenDeclVar declFunc = new TokenDeclVar(null, null, null);
+                    declFunc.name = new TokenName(null, key);
+                    declFunc.retType = TokenType.FromSysType(null, ifaceMethod.ReturnType);
+                    declFunc.argDecl = argDecl;
 
                     /*
                      * Add the TokenDeclVar struct to the dictionary.
                      */
-                    this.AddEntry (declFunc);
-                } catch (Exception except) {
+                    this.AddEntry(declFunc);
+                }
+                catch(Exception except)
+                {
 
-                    string msg = except.ToString ();
-                    int i = msg.IndexOf ("\n");
-                    if (i > 0) msg = msg.Substring (0, i);
-                    Console.WriteLine ("InternalFuncDict*: {0}:     {1}", key, msg);
+                    string msg = except.ToString();
+                    int i = msg.IndexOf("\n");
+                    if(i > 0)
+                        msg = msg.Substring(0, i);
+                    Console.WriteLine("InternalFuncDict*: {0}:     {1}", key, msg);
 
                     ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
                 }

+ 1569 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptBinOpStr.cs

@@ -0,0 +1,1569 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using OpenSim.Region.ScriptEngine.Yengine;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    /**
+     * @brief This class is used to catalog the code emit routines based on a key string
+     *        The key string has the two types (eg, "integer", "rotation") and the operator (eg, "*", "!=")
+     */
+    public delegate void BinOpStrEmitBO(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result);
+    public class BinOpStr
+    {
+        public static readonly Dictionary<string, BinOpStr> defined = DefineBinOps();
+
+        public Type outtype;           // type of result of computation
+        public BinOpStrEmitBO emitBO;  // how to compute result
+        public bool rmwOK;             // is the <operator>= form valid?
+
+        public BinOpStr(Type outtype, BinOpStrEmitBO emitBO)
+        {
+            this.outtype = outtype;
+            this.emitBO = emitBO;
+            this.rmwOK = false;
+        }
+
+        public BinOpStr(Type outtype, BinOpStrEmitBO emitBO, bool rmwOK)
+        {
+            this.outtype = outtype;
+            this.emitBO = emitBO;
+            this.rmwOK = rmwOK;
+        }
+
+        private static TokenTypeBool tokenTypeBool = new TokenTypeBool(null);
+        private static TokenTypeChar tokenTypeChar = new TokenTypeChar(null);
+        private static TokenTypeFloat tokenTypeFloat = new TokenTypeFloat(null);
+        private static TokenTypeInt tokenTypeInt = new TokenTypeInt(null);
+        private static TokenTypeList tokenTypeList = new TokenTypeList(null);
+        private static TokenTypeRot tokenTypeRot = new TokenTypeRot(null);
+        private static TokenTypeStr tokenTypeStr = new TokenTypeStr(null);
+        private static TokenTypeVec tokenTypeVec = new TokenTypeVec(null);
+
+        private static MethodInfo stringAddStringMethInfo = ScriptCodeGen.GetStaticMethod(typeof(string), "Concat", new Type[] { typeof(string), typeof(string) });
+        private static MethodInfo stringCmpStringMethInfo = ScriptCodeGen.GetStaticMethod(typeof(string), "Compare", new Type[] { typeof(string), typeof(string) });
+
+        private static MethodInfo infoMethListAddFloat = GetBinOpsMethod("MethListAddFloat", new Type[] { typeof(LSL_List), typeof(double) });
+        private static MethodInfo infoMethListAddInt = GetBinOpsMethod("MethListAddInt", new Type[] { typeof(LSL_List), typeof(int) });
+        private static MethodInfo infoMethListAddKey = GetBinOpsMethod("MethListAddKey", new Type[] { typeof(LSL_List), typeof(string) });
+        private static MethodInfo infoMethListAddRot = GetBinOpsMethod("MethListAddRot", new Type[] { typeof(LSL_List), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethListAddStr = GetBinOpsMethod("MethListAddStr", new Type[] { typeof(LSL_List), typeof(string) });
+        private static MethodInfo infoMethListAddVec = GetBinOpsMethod("MethListAddVec", new Type[] { typeof(LSL_List), typeof(LSL_Vector) });
+        private static MethodInfo infoMethListAddList = GetBinOpsMethod("MethListAddList", new Type[] { typeof(LSL_List), typeof(LSL_List) });
+        private static MethodInfo infoMethFloatAddList = GetBinOpsMethod("MethFloatAddList", new Type[] { typeof(double), typeof(LSL_List) });
+        private static MethodInfo infoMethIntAddList = GetBinOpsMethod("MethIntAddList", new Type[] { typeof(int), typeof(LSL_List) });
+        private static MethodInfo infoMethKeyAddList = GetBinOpsMethod("MethKeyAddList", new Type[] { typeof(string), typeof(LSL_List) });
+        private static MethodInfo infoMethRotAddList = GetBinOpsMethod("MethRotAddList", new Type[] { typeof(LSL_Rotation), typeof(LSL_List) });
+        private static MethodInfo infoMethStrAddList = GetBinOpsMethod("MethStrAddList", new Type[] { typeof(string), typeof(LSL_List) });
+        private static MethodInfo infoMethVecAddList = GetBinOpsMethod("MethVecAddList", new Type[] { typeof(LSL_Vector), typeof(LSL_List) });
+        private static MethodInfo infoMethListEqList = GetBinOpsMethod("MethListEqList", new Type[] { typeof(LSL_List), typeof(LSL_List) });
+        private static MethodInfo infoMethListNeList = GetBinOpsMethod("MethListNeList", new Type[] { typeof(LSL_List), typeof(LSL_List) });
+        private static MethodInfo infoMethRotEqRot = GetBinOpsMethod("MethRotEqRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethRotNeRot = GetBinOpsMethod("MethRotNeRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethRotAddRot = GetBinOpsMethod("MethRotAddRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethRotSubRot = GetBinOpsMethod("MethRotSubRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethRotMulRot = GetBinOpsMethod("MethRotMulRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethRotDivRot = GetBinOpsMethod("MethRotDivRot", new Type[] { typeof(LSL_Rotation), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethVecEqVec = GetBinOpsMethod("MethVecEqVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecNeVec = GetBinOpsMethod("MethVecNeVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecAddVec = GetBinOpsMethod("MethVecAddVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecSubVec = GetBinOpsMethod("MethVecSubVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecMulVec = GetBinOpsMethod("MethVecMulVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecModVec = GetBinOpsMethod("MethVecModVec", new Type[] { typeof(LSL_Vector), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecMulFloat = GetBinOpsMethod("MethVecMulFloat", new Type[] { typeof(LSL_Vector), typeof(double) });
+        private static MethodInfo infoMethFloatMulVec = GetBinOpsMethod("MethFloatMulVec", new Type[] { typeof(double), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecDivFloat = GetBinOpsMethod("MethVecDivFloat", new Type[] { typeof(LSL_Vector), typeof(double) });
+        private static MethodInfo infoMethVecMulInt = GetBinOpsMethod("MethVecMulInt", new Type[] { typeof(LSL_Vector), typeof(int) });
+        private static MethodInfo infoMethIntMulVec = GetBinOpsMethod("MethIntMulVec", new Type[] { typeof(int), typeof(LSL_Vector) });
+        private static MethodInfo infoMethVecDivInt = GetBinOpsMethod("MethVecDivInt", new Type[] { typeof(LSL_Vector), typeof(int) });
+        private static MethodInfo infoMethVecMulRot = GetBinOpsMethod("MethVecMulRot", new Type[] { typeof(LSL_Vector), typeof(LSL_Rotation) });
+        private static MethodInfo infoMethVecDivRot = GetBinOpsMethod("MethVecDivRot", new Type[] { typeof(LSL_Vector), typeof(LSL_Rotation) });
+
+        private static MethodInfo GetBinOpsMethod(string name, Type[] types)
+        {
+            return ScriptCodeGen.GetStaticMethod(typeof(BinOpStr), name, types);
+        }
+
+        /**
+         * @brief Create a dictionary for processing binary operators.
+         *        This tells us, for a given type, an operator and another type,
+         *        is the operation permitted, and if so, what is the type of the result?
+         * The key is <lefttype><opcode><righttype>,
+         *   where <lefttype> and <righttype> are strings returned by (TokenType...).ToString()
+         *   and <opcode> is string returned by (TokenKw...).ToString()
+         * The value is a BinOpStr struct giving the resultant type and a method to generate the code.
+         */
+        private static Dictionary<string, BinOpStr> DefineBinOps()
+        {
+            Dictionary<string, BinOpStr> bos = new Dictionary<string, BinOpStr>();
+
+            string[] booltypes = new string[] { "bool", "char", "float", "integer", "key", "list", "string" };
+
+            /*
+             * Get the && and || all out of the way...
+             * Simply cast their left and right operands to boolean then process.
+             */
+            for(int i = 0; i < booltypes.Length; i++)
+            {
+                for(int j = 0; j < booltypes.Length; j++)
+                {
+                    bos.Add(booltypes[i] + "&&" + booltypes[j],
+                             new BinOpStr(typeof(bool), BinOpStrAndAnd));
+                    bos.Add(booltypes[i] + "||" + booltypes[j],
+                             new BinOpStr(typeof(bool), BinOpStrOrOr));
+                }
+            }
+
+            /*
+             * Pound through all the other combinations we support.
+             */
+
+            // boolean : somethingelse
+            DefineBinOpsBoolX(bos, "bool");
+            DefineBinOpsBoolX(bos, "char");
+            DefineBinOpsBoolX(bos, "float");
+            DefineBinOpsBoolX(bos, "integer");
+            DefineBinOpsBoolX(bos, "key");
+            DefineBinOpsBoolX(bos, "list");
+            DefineBinOpsBoolX(bos, "string");
+
+            // stuff with chars
+            DefineBinOpsChar(bos);
+
+            // somethingelse : boolean
+            DefineBinOpsXBool(bos, "char");
+            DefineBinOpsXBool(bos, "float");
+            DefineBinOpsXBool(bos, "integer");
+            DefineBinOpsXBool(bos, "key");
+            DefineBinOpsXBool(bos, "list");
+            DefineBinOpsXBool(bos, "string");
+
+            // float : somethingelse
+            DefineBinOpsFloatX(bos, "float");
+            DefineBinOpsFloatX(bos, "integer");
+
+            // integer : float
+            DefineBinOpsXFloat(bos, "integer");
+
+            // anything else with integers
+            DefineBinOpsInteger(bos);
+
+            // key : somethingelse
+            DefineBinOpsKeyX(bos, "key");
+            DefineBinOpsKeyX(bos, "string");
+
+            // string : key
+            DefineBinOpsXKey(bos, "string");
+
+            // things with lists
+            DefineBinOpsList(bos);
+
+            // things with rotations
+            DefineBinOpsRotation(bos);
+
+            // things with strings
+            DefineBinOpsString(bos);
+
+            // things with vectors
+            DefineBinOpsVector(bos);
+
+            // Contrary to some beliefs, scripts do things like string+integer and integer+string
+            bos.Add("bool+string", new BinOpStr(typeof(string), BinOpStrStrAddStr));
+            bos.Add("char+string", new BinOpStr(typeof(string), BinOpStrStrAddStr));
+            bos.Add("float+string", new BinOpStr(typeof(string), BinOpStrStrAddStr));
+            bos.Add("integer+string", new BinOpStr(typeof(string), BinOpStrStrAddStr));
+            bos.Add("string+bool", new BinOpStr(typeof(string), BinOpStrStrAddStr, true));
+            bos.Add("string+char", new BinOpStr(typeof(string), BinOpStrStrAddStr, true));
+            bos.Add("string+float", new BinOpStr(typeof(string), BinOpStrStrAddStr, true));
+            bos.Add("string+integer", new BinOpStr(typeof(string), BinOpStrStrAddStr, true));
+
+            // Now for our final slight-of-hand, we're going to scan through all those.
+            // And wherever we see an 'integer' in the key, we are going to make another
+            // entry with 'bool', as we want to accept a bool as having a value of 0 or 1.
+            // This lets us do things like 3.5 * (x > 0).
+
+            Dictionary<string, BinOpStr> bos2 = new Dictionary<string, BinOpStr>();
+            foreach(KeyValuePair<string, BinOpStr> kvp in bos)
+            {
+                string key = kvp.Key;
+                BinOpStr val = kvp.Value;
+                bos2.Add(key, val);
+            }
+            Regex wordReg = new Regex("\\w+");
+            Regex opReg = new Regex("\\W+");
+            foreach(KeyValuePair<string, BinOpStr> kvp in bos)
+            {
+                string key = kvp.Key;
+                BinOpStr val = kvp.Value;
+                MatchCollection matches = wordReg.Matches(key);
+                if(matches.Count != 2)
+                    continue;
+                Match opM = opReg.Match(key);
+                if(!opM.Success)
+                    continue;
+                string left = matches[0].Value;
+                string right = matches[1].Value;
+                string op = opM.Value;
+                string key2;
+                if(left == "integer" && right == "integer")
+                {
+                    key2 = "bool" + op + "bool";
+                    if(!bos2.ContainsKey(key2))
+                        bos2.Add(key2, val);
+                    key2 = "bool" + op + "integer";
+                    if(!bos2.ContainsKey(key2))
+                        bos2.Add(key2, val);
+                    key2 = "integer" + op + "bool";
+                    if(!bos2.ContainsKey(key2))
+                        bos2.Add(key2, val);
+                }
+                else
+                {
+                    key2 = key.Replace("integer", "bool");
+                    if(!bos2.ContainsKey(key2))
+                        bos2.Add(key2, val);
+                }
+            }
+            return bos2;
+        }
+
+        private static void DefineBinOpsBoolX(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add("bool|" + x, new BinOpStr(typeof(int), BinOpStrBoolOrX));
+            bos.Add("bool^" + x, new BinOpStr(typeof(int), BinOpStrBoolXorX));
+            bos.Add("bool&" + x, new BinOpStr(typeof(int), BinOpStrBoolAndX));
+            bos.Add("bool==" + x, new BinOpStr(typeof(bool), BinOpStrBoolEqX));
+            bos.Add("bool!=" + x, new BinOpStr(typeof(bool), BinOpStrBoolNeX));
+        }
+
+        private static void DefineBinOpsXBool(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add(x + "|bool", new BinOpStr(typeof(int), BinOpStrBoolOrX));
+            bos.Add(x + "^bool", new BinOpStr(typeof(int), BinOpStrBoolXorX));
+            bos.Add(x + "&bool", new BinOpStr(typeof(int), BinOpStrBoolAndX));
+            bos.Add(x + "==bool", new BinOpStr(typeof(bool), BinOpStrBoolEqX));
+            bos.Add(x + "!=bool", new BinOpStr(typeof(bool), BinOpStrBoolNeX));
+        }
+
+        private static void DefineBinOpsFloatX(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add("float==" + x, new BinOpStr(typeof(bool), BinOpStrFloatEqX));
+            bos.Add("float!=" + x, new BinOpStr(typeof(bool), BinOpStrFloatNeX));
+            bos.Add("float<" + x, new BinOpStr(typeof(bool), BinOpStrFloatLtX));
+            bos.Add("float<=" + x, new BinOpStr(typeof(bool), BinOpStrFloatLeX));
+            bos.Add("float>" + x, new BinOpStr(typeof(bool), BinOpStrFloatGtX));
+            bos.Add("float>=" + x, new BinOpStr(typeof(bool), BinOpStrFloatGeX));
+            bos.Add("float+" + x, new BinOpStr(typeof(double), BinOpStrFloatAddX, true));
+            bos.Add("float-" + x, new BinOpStr(typeof(double), BinOpStrFloatSubX, true));
+            bos.Add("float*" + x, new BinOpStr(typeof(double), BinOpStrFloatMulX, true));
+            bos.Add("float/" + x, new BinOpStr(typeof(double), BinOpStrFloatDivX, true));
+            bos.Add("float%" + x, new BinOpStr(typeof(double), BinOpStrFloatModX, true));
+        }
+
+        private static void DefineBinOpsXFloat(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add(x + "==float", new BinOpStr(typeof(bool), BinOpStrXEqFloat));
+            bos.Add(x + "!=float", new BinOpStr(typeof(bool), BinOpStrXNeFloat));
+            bos.Add(x + "<float", new BinOpStr(typeof(bool), BinOpStrXLtFloat));
+            bos.Add(x + "<=float", new BinOpStr(typeof(bool), BinOpStrXLeFloat));
+            bos.Add(x + ">float", new BinOpStr(typeof(bool), BinOpStrXGtFloat));
+            bos.Add(x + ">=float", new BinOpStr(typeof(bool), BinOpStrXGeFloat));
+            bos.Add(x + "+float", new BinOpStr(typeof(double), BinOpStrXAddFloat, true));
+            bos.Add(x + "-float", new BinOpStr(typeof(double), BinOpStrXSubFloat, true));
+            bos.Add(x + "*float", new BinOpStr(typeof(double), BinOpStrXMulFloat, true));
+            bos.Add(x + "/float", new BinOpStr(typeof(double), BinOpStrXDivFloat, true));
+            bos.Add(x + "%float", new BinOpStr(typeof(double), BinOpStrXModFloat, true));
+        }
+
+        private static void DefineBinOpsChar(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("char==char", new BinOpStr(typeof(bool), BinOpStrCharEqChar));
+            bos.Add("char!=char", new BinOpStr(typeof(bool), BinOpStrCharNeChar));
+            bos.Add("char<char", new BinOpStr(typeof(bool), BinOpStrCharLtChar));
+            bos.Add("char<=char", new BinOpStr(typeof(bool), BinOpStrCharLeChar));
+            bos.Add("char>char", new BinOpStr(typeof(bool), BinOpStrCharGtChar));
+            bos.Add("char>=char", new BinOpStr(typeof(bool), BinOpStrCharGeChar));
+            bos.Add("char+integer", new BinOpStr(typeof(char), BinOpStrCharAddInt, true));
+            bos.Add("char-integer", new BinOpStr(typeof(char), BinOpStrCharSubInt, true));
+            bos.Add("char-char", new BinOpStr(typeof(int), BinOpStrCharSubChar));
+        }
+
+        private static void DefineBinOpsInteger(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("integer==integer", new BinOpStr(typeof(bool), BinOpStrIntEqInt));
+            bos.Add("integer!=integer", new BinOpStr(typeof(bool), BinOpStrIntNeInt));
+            bos.Add("integer<integer", new BinOpStr(typeof(bool), BinOpStrIntLtInt));
+            bos.Add("integer<=integer", new BinOpStr(typeof(bool), BinOpStrIntLeInt));
+            bos.Add("integer>integer", new BinOpStr(typeof(bool), BinOpStrIntGtInt));
+            bos.Add("integer>=integer", new BinOpStr(typeof(bool), BinOpStrIntGeInt));
+            bos.Add("integer|integer", new BinOpStr(typeof(int), BinOpStrIntOrInt, true));
+            bos.Add("integer^integer", new BinOpStr(typeof(int), BinOpStrIntXorInt, true));
+            bos.Add("integer&integer", new BinOpStr(typeof(int), BinOpStrIntAndInt, true));
+            bos.Add("integer+integer", new BinOpStr(typeof(int), BinOpStrIntAddInt, true));
+            bos.Add("integer-integer", new BinOpStr(typeof(int), BinOpStrIntSubInt, true));
+            bos.Add("integer*integer", new BinOpStr(typeof(int), BinOpStrIntMulInt, true));
+            bos.Add("integer/integer", new BinOpStr(typeof(int), BinOpStrIntDivInt, true));
+            bos.Add("integer%integer", new BinOpStr(typeof(int), BinOpStrIntModInt, true));
+            bos.Add("integer<<integer", new BinOpStr(typeof(int), BinOpStrIntShlInt, true));
+            bos.Add("integer>>integer", new BinOpStr(typeof(int), BinOpStrIntShrInt, true));
+        }
+
+        private static void DefineBinOpsKeyX(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add("key==" + x, new BinOpStr(typeof(bool), BinOpStrKeyEqX));
+            bos.Add("key!=" + x, new BinOpStr(typeof(bool), BinOpStrKeyNeX));
+        }
+
+        private static void DefineBinOpsXKey(Dictionary<string, BinOpStr> bos, string x)
+        {
+            bos.Add(x + "==key", new BinOpStr(typeof(bool), BinOpStrKeyEqX));
+            bos.Add(x + "!=key", new BinOpStr(typeof(bool), BinOpStrKeyNeX));
+        }
+
+        private static void DefineBinOpsList(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("list+float", new BinOpStr(typeof(LSL_List), BinOpStrListAddFloat, true));
+            bos.Add("list+integer", new BinOpStr(typeof(LSL_List), BinOpStrListAddInt, true));
+            bos.Add("list+key", new BinOpStr(typeof(LSL_List), BinOpStrListAddKey, true));
+            bos.Add("list+list", new BinOpStr(typeof(LSL_List), BinOpStrListAddList, true));
+            bos.Add("list+rotation", new BinOpStr(typeof(LSL_List), BinOpStrListAddRot, true));
+            bos.Add("list+string", new BinOpStr(typeof(LSL_List), BinOpStrListAddStr, true));
+            bos.Add("list+vector", new BinOpStr(typeof(LSL_List), BinOpStrListAddVec, true));
+
+            bos.Add("float+list", new BinOpStr(typeof(LSL_List), BinOpStrFloatAddList));
+            bos.Add("integer+list", new BinOpStr(typeof(LSL_List), BinOpStrIntAddList));
+            bos.Add("key+list", new BinOpStr(typeof(LSL_List), BinOpStrKeyAddList));
+            bos.Add("rotation+list", new BinOpStr(typeof(LSL_List), BinOpStrRotAddList));
+            bos.Add("string+list", new BinOpStr(typeof(LSL_List), BinOpStrStrAddList));
+            bos.Add("vector+list", new BinOpStr(typeof(LSL_List), BinOpStrVecAddList));
+
+            bos.Add("list==list", new BinOpStr(typeof(bool), BinOpStrListEqList));
+            bos.Add("list!=list", new BinOpStr(typeof(int), BinOpStrListNeList));
+        }
+
+        // all operations allowed by LSL_Rotation definition
+        private static void DefineBinOpsRotation(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("rotation==rotation", new BinOpStr(typeof(bool), BinOpStrRotEqRot));
+            bos.Add("rotation!=rotation", new BinOpStr(typeof(bool), BinOpStrRotNeRot));
+            bos.Add("rotation+rotation", new BinOpStr(typeof(LSL_Rotation), BinOpStrRotAddRot, true));
+            bos.Add("rotation-rotation", new BinOpStr(typeof(LSL_Rotation), BinOpStrRotSubRot, true));
+            bos.Add("rotation*rotation", new BinOpStr(typeof(LSL_Rotation), BinOpStrRotMulRot, true));
+            bos.Add("rotation/rotation", new BinOpStr(typeof(LSL_Rotation), BinOpStrRotDivRot, true));
+        }
+
+        private static void DefineBinOpsString(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("string==string", new BinOpStr(typeof(bool), BinOpStrStrEqStr));
+            bos.Add("string!=string", new BinOpStr(typeof(bool), BinOpStrStrNeStr));
+            bos.Add("string<string", new BinOpStr(typeof(bool), BinOpStrStrLtStr));
+            bos.Add("string<=string", new BinOpStr(typeof(bool), BinOpStrStrLeStr));
+            bos.Add("string>string", new BinOpStr(typeof(bool), BinOpStrStrGtStr));
+            bos.Add("string>=string", new BinOpStr(typeof(bool), BinOpStrStrGeStr));
+            bos.Add("string+string", new BinOpStr(typeof(string), BinOpStrStrAddStr, true));
+        }
+
+        // all operations allowed by LSL_Vector definition
+        private static void DefineBinOpsVector(Dictionary<string, BinOpStr> bos)
+        {
+            bos.Add("vector==vector", new BinOpStr(typeof(bool), BinOpStrVecEqVec));
+            bos.Add("vector!=vector", new BinOpStr(typeof(bool), BinOpStrVecNeVec));
+            bos.Add("vector+vector", new BinOpStr(typeof(LSL_Vector), BinOpStrVecAddVec, true));
+            bos.Add("vector-vector", new BinOpStr(typeof(LSL_Vector), BinOpStrVecSubVec, true));
+            bos.Add("vector*vector", new BinOpStr(typeof(double), BinOpStrVecMulVec));
+            bos.Add("vector%vector", new BinOpStr(typeof(LSL_Vector), BinOpStrVecModVec, true));
+
+            bos.Add("vector*float", new BinOpStr(typeof(LSL_Vector), BinOpStrVecMulFloat, true));
+            bos.Add("float*vector", new BinOpStr(typeof(LSL_Vector), BinOpStrFloatMulVec));
+            bos.Add("vector/float", new BinOpStr(typeof(LSL_Vector), BinOpStrVecDivFloat, true));
+
+            bos.Add("vector*integer", new BinOpStr(typeof(LSL_Vector), BinOpStrVecMulInt, true));
+            bos.Add("integer*vector", new BinOpStr(typeof(LSL_Vector), BinOpStrIntMulVec));
+            bos.Add("vector/integer", new BinOpStr(typeof(LSL_Vector), BinOpStrVecDivInt, true));
+
+            bos.Add("vector*rotation", new BinOpStr(typeof(LSL_Vector), BinOpStrVecMulRot, true));
+            bos.Add("vector/rotation", new BinOpStr(typeof(LSL_Vector), BinOpStrVecDivRot, true));
+        }
+
+        /**
+         * @brief These methods actually emit the code to perform the arithmetic.
+         * @param scg    = what script we are compiling
+         * @param left   = left-hand operand location in memory (type as given by BinOpStr entry)
+         * @param right  = right-hand operand location in memory (type as given by BinOpStr entry)
+         * @param result = result location in memory (type as given by BinOpStr entry)
+         */
+        private static void BinOpStrAndAnd(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeBool);
+            right.PushVal(scg, errorAt, tokenTypeBool);
+            scg.ilGen.Emit(errorAt, OpCodes.And);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrOrOr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeBool);
+            right.PushVal(scg, errorAt, tokenTypeBool);
+            scg.ilGen.Emit(errorAt, OpCodes.Or);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrBoolOrX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Or);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrBoolXorX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrBoolAndX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.And);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrBoolEqX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeBool);
+            right.PushVal(scg, errorAt, tokenTypeBool);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrBoolNeX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeBool);
+            right.PushVal(scg, errorAt, tokenTypeBool);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatEqX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatNeX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatLtX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatLeX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatGtX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatGeX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrFloatAddX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Add);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrFloatSubX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Sub);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrFloatMulX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Mul);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrFloatDivX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Div);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrFloatModX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Rem);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrXEqFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXNeFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXLtFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXLeFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXGtFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXGeFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrXAddFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Add);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrXSubFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Sub);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrXMulFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Mul);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrXDivFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Div);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrXModFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Rem);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrCharEqChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharNeChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharLtChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharLeChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharGtChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharGeChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrCharAddInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Add);
+            result.PopPost(scg, errorAt, tokenTypeChar);
+        }
+
+        private static void BinOpStrCharSubInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Sub);
+            result.PopPost(scg, errorAt, tokenTypeChar);
+        }
+
+        private static void BinOpStrCharSubChar(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeChar);
+            right.PushVal(scg, errorAt, tokenTypeChar);
+            scg.ilGen.Emit(errorAt, OpCodes.Sub);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntEqInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntNeInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntLtInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntLeInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntGtInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntGeInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrIntOrInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Or);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntXorInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntAndInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.And);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntAddInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Add);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntSubInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Sub);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntMulInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Mul);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntDivInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            // note that we must allow 0x800000/-1 -> 0x80000000 for lslangtest1.lsl
+            // so sign-extend the operands to 64-bit then divide and truncate result
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I8);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I8);
+            scg.ilGen.Emit(errorAt, OpCodes.Div);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I4);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntModInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            // note that we must allow 0x800000%-1 -> 0 for lslangtest1.lsl
+            // so sign-extend the operands to 64-bit then mod and truncate result
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I8);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I8);
+            scg.ilGen.Emit(errorAt, OpCodes.Rem);
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I4);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntShlInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Shl);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrIntShrInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Shr);
+            result.PopPost(scg, errorAt, tokenTypeInt);
+        }
+
+        private static void BinOpStrKeyEqX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrKeyNeX(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrListAddFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddFloat);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddInt);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddKey(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddKey);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddRot);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddStr);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListAddVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListAddVec);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrFloatAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethFloatAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrIntAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethIntAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrKeyAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethKeyAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrRotAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrStrAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethStrAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrVecAddList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecAddList);
+            result.PopPost(scg, errorAt, tokenTypeList);
+        }
+
+        private static void BinOpStrListEqList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListEqList);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrListNeList(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeList);
+            right.PushVal(scg, errorAt, tokenTypeList);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethListNeList);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrRotEqRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotEqRot);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrRotNeRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotNeRot);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrRotAddRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotAddRot);
+            result.PopPost(scg, errorAt, tokenTypeRot);
+        }
+
+        private static void BinOpStrRotSubRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotSubRot);
+            result.PopPost(scg, errorAt, tokenTypeRot);
+        }
+
+        private static void BinOpStrRotMulRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotMulRot);
+            result.PopPost(scg, errorAt, tokenTypeRot);
+        }
+
+        private static void BinOpStrRotDivRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeRot);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethRotDivRot);
+            result.PopPost(scg, errorAt, tokenTypeRot);
+        }
+
+        private static void BinOpStrStrEqStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrStrNeStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrStrLtStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrStrLeStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Clt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrStrGtStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrStrGeStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringCmpStringMethInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_M1);
+            scg.ilGen.Emit(errorAt, OpCodes.Cgt);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        // Called by many type combinations so both operands need to be cast to strings
+        private static void BinOpStrStrAddStr(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeStr);
+            right.PushVal(scg, errorAt, tokenTypeStr);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringAddStringMethInfo);
+            result.PopPost(scg, errorAt, tokenTypeStr);
+        }
+
+        private static void BinOpStrVecEqVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecEqVec);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrVecNeVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecNeVec);
+            result.PopPost(scg, errorAt, tokenTypeBool);
+        }
+
+        private static void BinOpStrVecAddVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecAddVec);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecSubVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecSubVec);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecMulVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecMulVec);
+            result.PopPost(scg, errorAt, tokenTypeFloat);
+        }
+
+        private static void BinOpStrVecModVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecModVec);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecMulFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecMulFloat);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrFloatMulVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeFloat);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethFloatMulVec);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecDivFloat(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeFloat);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecDivFloat);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecMulInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecMulInt);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrIntMulVec(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeInt);
+            right.PushVal(scg, errorAt, tokenTypeVec);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethIntMulVec);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecDivInt(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeInt);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecDivInt);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecMulRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecMulRot);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        private static void BinOpStrVecDivRot(ScriptCodeGen scg, Token errorAt, CompValu left, CompValu right, CompValu result)
+        {
+            result.PopPre(scg, errorAt);
+            left.PushVal(scg, errorAt, tokenTypeVec);
+            right.PushVal(scg, errorAt, tokenTypeRot);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, infoMethVecDivRot);
+            result.PopPost(scg, errorAt, tokenTypeVec);
+        }
+
+        /**
+         * @brief These methods are called at runtime as helpers.
+         *        Needed to pick up functionality defined by overloaded operators of LSL_ types.
+         *        They need to be marked public or runtime says they are inaccessible.
+         */
+        public static LSL_List MethListAddFloat(LSL_List left, double right)
+        {
+            return MethListAddObj(left, new LSL_Float(right));
+        }
+        public static LSL_List MethListAddInt(LSL_List left, int right)
+        {
+            return MethListAddObj(left, new LSL_Integer(right));
+        }
+        public static LSL_List MethListAddKey(LSL_List left, string right)
+        {
+            return MethListAddObj(left, new LSL_Key(right));
+        }
+        public static LSL_List MethListAddRot(LSL_List left, LSL_Rotation right)
+        {
+            return MethListAddObj(left, right);
+        }
+        public static LSL_List MethListAddStr(LSL_List left, string right)
+        {
+            return MethListAddObj(left, new LSL_String(right));
+        }
+        public static LSL_List MethListAddVec(LSL_List left, LSL_Vector right)
+        {
+            return MethListAddObj(left, right);
+        }
+        public static LSL_List MethListAddObj(LSL_List left, object right)
+        {
+            int oldlen = left.Length;
+            object[] newarr = new object[oldlen + 1];
+            Array.Copy(left.Data, newarr, oldlen);
+            newarr[oldlen] = right;
+            return new LSL_List(newarr);
+        }
+
+        public static LSL_List MethListAddList(LSL_List left, LSL_List right)
+        {
+            int leftlen = left.Length;
+            int ritelen = right.Length;
+            object[] newarr = new object[leftlen + ritelen];
+            Array.Copy(left.Data, newarr, leftlen);
+            Array.Copy(right.Data, 0, newarr, leftlen, ritelen);
+            return new LSL_List(newarr);
+        }
+
+        public static LSL_List MethFloatAddList(double left, LSL_List right)
+        {
+            return MethObjAddList(new LSL_Float(left), right);
+        }
+        public static LSL_List MethIntAddList(int left, LSL_List right)
+        {
+            return MethObjAddList(new LSL_Integer(left), right);
+        }
+        public static LSL_List MethKeyAddList(string left, LSL_List right)
+        {
+            return MethObjAddList(new LSL_Key(left), right);
+        }
+        public static LSL_List MethRotAddList(LSL_Rotation left, LSL_List right)
+        {
+            return MethObjAddList(left, right);
+        }
+        public static LSL_List MethStrAddList(string left, LSL_List right)
+        {
+            return MethObjAddList(new LSL_String(left), right);
+        }
+        public static LSL_List MethVecAddList(LSL_Vector left, LSL_List right)
+        {
+            return MethObjAddList(left, right);
+        }
+        public static LSL_List MethObjAddList(object left, LSL_List right)
+        {
+            int oldlen = right.Length;
+            object[] newarr = new object[oldlen + 1];
+            newarr[0] = left;
+            Array.Copy(right.Data, 0, newarr, 1, oldlen);
+            return new LSL_List(newarr);
+        }
+
+        public static bool MethListEqList(LSL_List left, LSL_List right)
+        {
+            return left == right;
+        }
+
+        // According to http://wiki.secondlife.com/wiki/LlGetListLength
+        // jackassed LSL allows 'somelist != []' to get the length of a list
+        public static int MethListNeList(LSL_List left, LSL_List right)
+        {
+            int leftlen = left.Length;
+            int ritelen = right.Length;
+            return leftlen - ritelen;
+        }
+
+        public static bool MethRotEqRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left == right;
+        }
+
+        public static bool MethRotNeRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left != right;
+        }
+
+        public static LSL_Rotation MethRotAddRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left + right;
+        }
+
+        public static LSL_Rotation MethRotSubRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left - right;
+        }
+
+        public static LSL_Rotation MethRotMulRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Rotation MethRotDivRot(LSL_Rotation left, LSL_Rotation right)
+        {
+            return left / right;
+        }
+
+        public static bool MethVecEqVec(LSL_Vector left, LSL_Vector right)
+        {
+            return left == right;
+        }
+
+        public static bool MethVecNeVec(LSL_Vector left, LSL_Vector right)
+        {
+            return left != right;
+        }
+
+        public static LSL_Vector MethVecAddVec(LSL_Vector left, LSL_Vector right)
+        {
+            return left + right;
+        }
+
+        public static LSL_Vector MethVecSubVec(LSL_Vector left, LSL_Vector right)
+        {
+            return left - right;
+        }
+
+        public static double MethVecMulVec(LSL_Vector left, LSL_Vector right)
+        {
+            return (double)(left * right).value;
+        }
+
+        public static LSL_Vector MethVecModVec(LSL_Vector left, LSL_Vector right)
+        {
+            return left % right;
+        }
+
+        public static LSL_Vector MethVecMulFloat(LSL_Vector left, double right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Vector MethFloatMulVec(double left, LSL_Vector right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Vector MethVecDivFloat(LSL_Vector left, double right)
+        {
+            return left / right;
+        }
+
+        public static LSL_Vector MethVecMulInt(LSL_Vector left, int right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Vector MethIntMulVec(int left, LSL_Vector right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Vector MethVecDivInt(LSL_Vector left, int right)
+        {
+            return left / right;
+        }
+
+        public static LSL_Vector MethVecMulRot(LSL_Vector left, LSL_Rotation right)
+        {
+            return left * right;
+        }
+
+        public static LSL_Vector MethVecDivRot(LSL_Vector left, LSL_Rotation right)
+        {
+            return left / right;
+        }
+    }
+}

+ 7170 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs

@@ -0,0 +1,7170 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using OpenSim.Region.ScriptEngine.Yengine;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Threading;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * @brief translate a reduced script token into corresponding CIL code.
+ * The single script token contains a tokenized and textured version of the whole script file.
+ */
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public interface IScriptCodeGen
+    {
+        ScriptMyILGen ilGen
+        {
+            get;
+        } // the output instruction stream
+        void ErrorMsg(Token token, string message);
+        void PushDefaultValue(TokenType type);
+        void PushXMRInst();
+    }
+
+    public class ScriptCodeGen: IScriptCodeGen
+    {
+        private static readonly bool DEBUG_STACKCAPRES = false;
+        private static readonly bool DEBUG_TRYSTMT = false;
+
+        public static readonly string OBJECT_CODE_MAGIC = "XMRObjectCode";
+        // reserve positive version values for original xmr
+        public static int COMPILED_VERSION_VALUE = -1;  // decremented when compiler or object file changes
+
+        public static readonly int CALL_FRAME_MEMUSE = 64;
+        public static readonly int STRING_LEN_TO_MEMUSE = 2;
+
+        public static Type xmrInstSuperType = null;  // typeof whatever is actually malloc'd for script instances
+                                                     // - must inherit from XMRInstAbstract
+
+        /*
+         * Static tables that there only needs to be one copy of for all.
+         */
+        private static VarDict legalEventHandlers = CreateLegalEventHandlers();
+        private static CompValu[] zeroCompValus = new CompValu[0];
+        private static TokenType[] zeroArgs = new TokenType[0];
+        private static TokenTypeBool tokenTypeBool = new TokenTypeBool(null);
+        private static TokenTypeExc tokenTypeExc = new TokenTypeExc(null);
+        private static TokenTypeFloat tokenTypeFlt = new TokenTypeFloat(null);
+        private static TokenTypeInt tokenTypeInt = new TokenTypeInt(null);
+        private static TokenTypeObject tokenTypeObj = new TokenTypeObject(null);
+        private static TokenTypeRot tokenTypeRot = new TokenTypeRot(null);
+        private static TokenTypeStr tokenTypeStr = new TokenTypeStr(null);
+        private static TokenTypeVec tokenTypeVec = new TokenTypeVec(null);
+        private static Type[] instanceTypeArg = new Type[] { typeof(XMRInstAbstract) };
+        private static string[] instanceNameArg = new string[] { "$xmrthis" };
+
+        private static ConstructorInfo lslFloatConstructorInfo = typeof(LSL_Float).GetConstructor(new Type[] { typeof(double) });
+        private static ConstructorInfo lslIntegerConstructorInfo = typeof(LSL_Integer).GetConstructor(new Type[] { typeof(int) });
+        private static ConstructorInfo lslListConstructorInfo = typeof(LSL_List).GetConstructor(new Type[] { typeof(object[]) });
+        public static ConstructorInfo lslRotationConstructorInfo = typeof(LSL_Rotation).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double), typeof(double) });
+        private static ConstructorInfo lslStringConstructorInfo = typeof(LSL_String).GetConstructor(new Type[] { typeof(string) });
+        public static ConstructorInfo lslVectorConstructorInfo = typeof(LSL_Vector).GetConstructor(new Type[] { typeof(double), typeof(double), typeof(double) });
+        private static ConstructorInfo scriptBadCallNoExceptionConstructorInfo = typeof(ScriptBadCallNoException).GetConstructor(new Type[] { typeof(int) });
+        private static ConstructorInfo scriptChangeStateExceptionConstructorInfo = typeof(ScriptChangeStateException).GetConstructor(new Type[] { typeof(int) });
+        private static ConstructorInfo scriptRestoreCatchExceptionConstructorInfo = typeof(ScriptRestoreCatchException).GetConstructor(new Type[] { typeof(Exception) });
+        private static ConstructorInfo scriptUndefinedStateExceptionConstructorInfo = typeof(ScriptUndefinedStateException).GetConstructor(new Type[] { typeof(string) });
+        private static ConstructorInfo sdtClassConstructorInfo = typeof(XMRSDTypeClObj).GetConstructor(new Type[] { typeof(XMRInstAbstract), typeof(int) });
+        private static ConstructorInfo xmrArrayConstructorInfo = typeof(XMR_Array).GetConstructor(new Type[] { typeof(XMRInstAbstract) });
+        private static FieldInfo callModeFieldInfo = typeof(XMRInstAbstract).GetField("callMode");
+        private static FieldInfo doGblInitFieldInfo = typeof(XMRInstAbstract).GetField("doGblInit");
+        private static FieldInfo ehArgsFieldInfo = typeof(XMRInstAbstract).GetField("ehArgs");
+        private static FieldInfo rotationXFieldInfo = typeof(LSL_Rotation).GetField("x");
+        private static FieldInfo rotationYFieldInfo = typeof(LSL_Rotation).GetField("y");
+        private static FieldInfo rotationZFieldInfo = typeof(LSL_Rotation).GetField("z");
+        private static FieldInfo rotationSFieldInfo = typeof(LSL_Rotation).GetField("s");
+        private static FieldInfo sdtXMRInstFieldInfo = typeof(XMRSDTypeClObj).GetField("xmrInst");
+        private static FieldInfo stackLeftFieldInfo = typeof(XMRInstAbstract).GetField("m_StackLeft");
+        private static FieldInfo vectorXFieldInfo = typeof(LSL_Vector).GetField("x");
+        private static FieldInfo vectorYFieldInfo = typeof(LSL_Vector).GetField("y");
+        private static FieldInfo vectorZFieldInfo = typeof(LSL_Vector).GetField("z");
+
+        private static MethodInfo arrayClearMethodInfo = typeof(XMR_Array).GetMethod("__pub_clear", new Type[] { });
+        private static MethodInfo arrayCountMethodInfo = typeof(XMR_Array).GetMethod("__pub_count", new Type[] { });
+        private static MethodInfo arrayIndexMethodInfo = typeof(XMR_Array).GetMethod("__pub_index", new Type[] { typeof(int) });
+        private static MethodInfo arrayValueMethodInfo = typeof(XMR_Array).GetMethod("__pub_value", new Type[] { typeof(int) });
+        private static MethodInfo checkRunStackMethInfo = typeof(XMRInstAbstract).GetMethod("CheckRunStack", new Type[] { });
+        private static MethodInfo checkRunQuickMethInfo = typeof(XMRInstAbstract).GetMethod("CheckRunQuick", new Type[] { });
+        private static MethodInfo ehArgUnwrapFloat = GetStaticMethod(typeof(TypeCast), "EHArgUnwrapFloat", new Type[] { typeof(object) });
+        private static MethodInfo ehArgUnwrapInteger = GetStaticMethod(typeof(TypeCast), "EHArgUnwrapInteger", new Type[] { typeof(object) });
+        private static MethodInfo ehArgUnwrapRotation = GetStaticMethod(typeof(TypeCast), "EHArgUnwrapRotation", new Type[] { typeof(object) });
+        private static MethodInfo ehArgUnwrapString = GetStaticMethod(typeof(TypeCast), "EHArgUnwrapString", new Type[] { typeof(object) });
+        private static MethodInfo ehArgUnwrapVector = GetStaticMethod(typeof(TypeCast), "EHArgUnwrapVector", new Type[] { typeof(object) });
+        private static MethodInfo xmrArrPubIndexMethod = typeof(XMR_Array).GetMethod("__pub_index", new Type[] { typeof(int) });
+        private static MethodInfo xmrArrPubValueMethod = typeof(XMR_Array).GetMethod("__pub_value", new Type[] { typeof(int) });
+        private static MethodInfo captureStackFrameMethodInfo = typeof(XMRInstAbstract).GetMethod("CaptureStackFrame", new Type[] { typeof(string), typeof(int), typeof(int) });
+        private static MethodInfo restoreStackFrameMethodInfo = typeof(XMRInstAbstract).GetMethod("RestoreStackFrame", new Type[] { typeof(string), typeof(int).MakeByRefType() });
+        private static MethodInfo stringCompareMethodInfo = GetStaticMethod(typeof(String), "Compare", new Type[] { typeof(string), typeof(string), typeof(StringComparison) });
+        private static MethodInfo stringConcat2MethodInfo = GetStaticMethod(typeof(String), "Concat", new Type[] { typeof(string), typeof(string) });
+        private static MethodInfo stringConcat3MethodInfo = GetStaticMethod(typeof(String), "Concat", new Type[] { typeof(string), typeof(string), typeof(string) });
+        private static MethodInfo stringConcat4MethodInfo = GetStaticMethod(typeof(String), "Concat", new Type[] { typeof(string), typeof(string), typeof(string), typeof(string) });
+        private static MethodInfo lslRotationNegateMethodInfo = GetStaticMethod(typeof(ScriptCodeGen),
+                                                                                 "LSLRotationNegate",
+                                                                                 new Type[] { typeof(LSL_Rotation) });
+        private static MethodInfo lslVectorNegateMethodInfo = GetStaticMethod(typeof(ScriptCodeGen),
+                                                                               "LSLVectorNegate",
+                                                                               new Type[] { typeof(LSL_Vector) });
+        private static MethodInfo scriptRestoreCatchExceptionUnwrap = GetStaticMethod(typeof(ScriptRestoreCatchException), "Unwrap", new Type[] { typeof(Exception) });
+        private static MethodInfo thrownExceptionWrapMethodInfo = GetStaticMethod(typeof(ScriptThrownException), "Wrap", new Type[] { typeof(object) });
+
+        private static MethodInfo catchExcToStrMethodInfo = GetStaticMethod(typeof(ScriptCodeGen),
+                                                                             "CatchExcToStr",
+                                                                             new Type[] { typeof(Exception) });
+
+        private static MethodInfo consoleWriteMethodInfo = GetStaticMethod(typeof(ScriptCodeGen), "ConsoleWrite", new Type[] { typeof(object) });
+        public static void ConsoleWrite(object o)
+        {
+            if(o == null)
+                o = "<<null>>";
+            Console.Write(o.ToString());
+        }
+
+        public static bool CodeGen(TokenScript tokenScript, BinaryWriter objFileWriter, string sourceHash)
+        {
+            /*
+             * Run compiler such that it has a 'this' context for convenience.
+             */
+            ScriptCodeGen scg = new ScriptCodeGen(tokenScript, objFileWriter, sourceHash);
+
+            /*
+             * Return pointer to resultant script object code.
+             */
+            return !scg.youveAnError;
+        }
+
+        /*
+         * There is one set of these variables for each script being compiled.
+         */
+        private bool mightGetHere = false;
+        private bool youveAnError = false;
+        private BreakContTarg curBreakTarg = null;
+        private BreakContTarg curContTarg = null;
+        private int lastErrorLine = 0;
+        private int nStates = 0;
+        private string sourceHash;
+        private string lastErrorFile = "";
+        private string[] stateNames;
+        private XMRInstArSizes glblSizes = new XMRInstArSizes();
+        private Token errorMessageToken = null;
+        private TokenDeclVar curDeclFunc = null;
+        private TokenStmtBlock curStmtBlock = null;
+        private BinaryWriter objFileWriter = null;
+        private TokenScript tokenScript = null;
+        public int tempCompValuNum = 0;
+        private TokenDeclSDTypeClass currentSDTClass = null;
+
+        private Dictionary<string, int> stateIndices = null;
+
+        // These get cleared at beginning of every function definition
+        private ScriptMyLocal instancePointer;   // holds XMRInstanceSuperType pointer
+        private ScriptMyLabel retLabel = null;  // where to jump to exit function
+        private ScriptMyLocal retValue = null;
+        private ScriptMyLocal actCallNo = null;  // for the active try/catch/finally stack or the big one outside them all
+        private LinkedList<CallLabel> actCallLabels = new LinkedList<CallLabel>();  // for the active try/catch/finally stack or the big one outside them all
+        private LinkedList<CallLabel> allCallLabels = new LinkedList<CallLabel>();  // this holds each and every one for all stacks in total
+        public CallLabel openCallLabel = null;  // only one call label can be open at a time
+                                                // - the call label is open from the time of CallPre() until corresponding CallPost()
+                                                // - so no non-trivial pushes/pops etc allowed between a CallPre() and a CallPost()
+
+        private ScriptMyILGen _ilGen;
+        public ScriptMyILGen ilGen
+        {
+            get
+            {
+                return _ilGen;
+            }
+        }
+
+        private ScriptCodeGen(TokenScript tokenScript, BinaryWriter objFileWriter, string sourceHash)
+        {
+            this.tokenScript = tokenScript;
+            this.objFileWriter = objFileWriter;
+            this.sourceHash = sourceHash;
+
+            try
+            {
+                PerformCompilation();
+            }
+            catch
+            {
+                // if we've an error, just punt on any exception
+                // it's probably just a null reference from something
+                // not being filled in etc.
+                if(!youveAnError)
+                    throw;
+            }
+            finally
+            {
+                objFileWriter = null;
+            }
+        }
+
+        /**
+         * @brief Convert 'tokenScript' to 'objFileWriter' format.
+         *   'tokenScript' is a parsed/reduced abstract syntax tree of the script source file
+         *   'objFileWriter' is a serialized form of the CIL code that we generate
+         */
+        private void PerformCompilation()
+        {
+            /*
+             * errorMessageToken is used only when the given token doesn't have a
+             * output delegate associated with it such as for backend API functions
+             * that only have one copy for the whole system.  It is kept up-to-date
+             * approximately but is rarely needed so going to assume it doesn't have 
+             * to be exact.
+             */
+            errorMessageToken = tokenScript;
+
+            /*
+             * Set up dictionary to translate state names to their index number.
+             */
+            stateIndices = new Dictionary<string, int>();
+
+            /*
+             * Assign each state its own unique index.
+             * The default state gets 0.
+             */
+            nStates = 0;
+            tokenScript.defaultState.body.index = nStates++;
+            stateIndices.Add("default", 0);
+            foreach(KeyValuePair<string, TokenDeclState> kvp in tokenScript.states)
+            {
+                TokenDeclState declState = kvp.Value;
+                declState.body.index = nStates++;
+                stateIndices.Add(declState.name.val, declState.body.index);
+            }
+
+            /*
+             * Make up an array that translates state indices to state name strings.
+             */
+            stateNames = new string[nStates];
+            stateNames[0] = "default";
+            foreach(KeyValuePair<string, TokenDeclState> kvp in tokenScript.states)
+            {
+                TokenDeclState declState = kvp.Value;
+                stateNames[declState.body.index] = declState.name.val;
+            }
+
+            /*
+             * Make sure we have delegates for all script-defined functions and methods,
+             * creating anonymous ones if needed.  Note that this includes all property 
+             * getter and setter methods.
+             */
+            foreach(TokenDeclVar declFunc in tokenScript.variablesStack)
+            {
+                if(declFunc.retType != null)
+                {
+                    declFunc.GetDelType();
+                }
+            }
+            while(true)
+            {
+                bool itIsAGoodDayToDie = true;
+                try
+                {
+                    foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+                    {
+                        itIsAGoodDayToDie = false;
+                        if(sdType is TokenDeclSDTypeClass)
+                        {
+                            TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+                            foreach(TokenDeclVar declFunc in sdtClass.members)
+                            {
+                                if(declFunc.retType != null)
+                                {
+                                    declFunc.GetDelType();
+                                    if(declFunc.funcNameSig.val.StartsWith("$ctor("))
+                                    {
+                                        // this is for the "$new()" static method that we create below.
+                                        // See GenerateStmtNewobj() etc.
+                                        new TokenTypeSDTypeDelegate(declFunc, sdtClass.MakeRefToken(declFunc),
+                                                declFunc.argDecl.types, tokenScript);
+                                    }
+                                }
+                            }
+                        }
+                        if(sdType is TokenDeclSDTypeInterface)
+                        {
+                            TokenDeclSDTypeInterface sdtIFace = (TokenDeclSDTypeInterface)sdType;
+                            foreach(TokenDeclVar declFunc in sdtIFace.methsNProps)
+                            {
+                                if(declFunc.retType != null)
+                                {
+                                    declFunc.GetDelType();
+                                }
+                            }
+                        }
+                        itIsAGoodDayToDie = true;
+                    }
+                    break;
+                }
+                catch(InvalidOperationException)
+                {
+                    if(!itIsAGoodDayToDie)
+                        throw;
+                    // fetching the delegate created an anonymous entry in tokenScript.sdSrcTypesValues
+                    // which made the foreach statement puque, so start over...
+                }
+            }
+
+            /*
+             * No more types can be defined or we won't be able to write them to the object file.
+             */
+            tokenScript.sdSrcTypesSeal();
+
+            /*
+             * Assign all global variables a slot in its corresponding XMRInstance.gbl<Type>s[] array.
+             * Global variables are simply elements of those arrays at runtime, thus we don't need to create
+             * an unique class for each script, we can just use XMRInstance as is for all.
+             */
+            foreach(TokenDeclVar declVar in tokenScript.variablesStack)
+            {
+
+                /*
+                 * Omit 'constant' variables as they are coded inline so don't need a slot.
+                 */
+                if(declVar.constant)
+                    continue;
+
+                /*
+                 * Do functions later.
+                 */
+                if(declVar.retType != null)
+                    continue;
+
+                /*
+                 * Create entry in the value array for the variable or property.
+                 */
+                declVar.location = new CompValuGlobalVar(declVar, glblSizes);
+            }
+
+            /*
+             * Likewise for any static fields in script-defined classes.
+             * They can be referenced anywhere by <typename>.<fieldname>, see 
+             * GenerateFromLValSField().
+             */
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                if(!(sdType is TokenDeclSDTypeClass))
+                    continue;
+                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+
+                foreach(TokenDeclVar declVar in sdtClass.members)
+                {
+
+                    /*
+                     * Omit 'constant' variables as they are coded inline so don't need a slot.
+                     */
+                    if(declVar.constant)
+                        continue;
+
+                    /*
+                     * Do methods later.
+                     */
+                    if(declVar.retType != null)
+                        continue;
+
+                    /*
+                     * Ignore non-static fields for now.
+                     * They get assigned below.
+                     */
+                    if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) == 0)
+                        continue;
+
+                    /*
+                     * Create entry in the value array for the static field or static property.
+                     */
+                    declVar.location = new CompValuGlobalVar(declVar, glblSizes);
+                }
+            }
+
+            /*
+             * Assign slots for all interface method prototypes.
+             * These indices are used to index the array of delegates that holds a class' implementation of an 
+             * interface.
+             * Properties do not get a slot because they aren't called as such.  But their corresponding
+             * <name>$get() and <name>$set(<type>) methods are in the table and they each get a slot.
+             */
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                if(!(sdType is TokenDeclSDTypeInterface))
+                    continue;
+                TokenDeclSDTypeInterface sdtIFace = (TokenDeclSDTypeInterface)sdType;
+                int vti = 0;
+                foreach(TokenDeclVar im in sdtIFace.methsNProps)
+                {
+                    if((im.getProp == null) && (im.setProp == null))
+                    {
+                        im.vTableIndex = vti++;
+                    }
+                }
+            }
+
+            /*
+             * Assign slots for all instance fields and virtual methods of script-defined classes.
+             */
+            int maxExtends = tokenScript.sdSrcTypesCount;
+            bool didOne;
+            do
+            {
+                didOne = false;
+                foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+                {
+                    if(!(sdType is TokenDeclSDTypeClass))
+                        continue;
+                    TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+                    if(sdtClass.slotsAssigned)
+                        continue;
+
+                    /*
+                     * If this class extends another, the extended class has to already 
+                     * be set up, because our slots add on to the end of the extended class.
+                     */
+                    TokenDeclSDTypeClass extends = sdtClass.extends;
+                    if(extends != null)
+                    {
+                        if(!extends.slotsAssigned)
+                            continue;
+                        sdtClass.instSizes = extends.instSizes;
+                        sdtClass.numVirtFuncs = extends.numVirtFuncs;
+                        sdtClass.numInterfaces = extends.numInterfaces;
+
+                        int n = maxExtends;
+                        for(TokenDeclSDTypeClass ex = extends; ex != null; ex = ex.extends)
+                        {
+                            if(--n < 0)
+                                break;
+                        }
+                        if(n < 0)
+                        {
+                            ErrorMsg(sdtClass, "loop in extended classes");
+                            sdtClass.slotsAssigned = true;
+                            continue;
+                        }
+                    }
+
+                    /*
+                     * Extended class's slots all assigned, assign our instance fields 
+                     * slots in the XMRSDTypeClObj arrays.
+                     */
+                    foreach(TokenDeclVar declVar in sdtClass.members)
+                    {
+                        if(declVar.retType != null)
+                            continue;
+                        if(declVar.constant)
+                            continue;
+                        if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+                            continue;
+                        if((declVar.getProp == null) && (declVar.setProp == null))
+                        {
+                            declVar.type.AssignVarSlot(declVar, sdtClass.instSizes);
+                        }
+                    }
+
+                    /*
+                     * ... and assign virtual method vtable slots.
+                     *
+                     *                   - : error if any overridden method, doesn't need a slot
+                     *            abstract : error if any overridden method, alloc new slot but leave it empty
+                     *                 new : ignore any overridden method, doesn't need a slot
+                     *        new abstract : ignore any overridden method, alloc new slot but leave it empty
+                     *            override : must have overridden abstract/virtual, use old slot
+                     *   override abstract : must have overridden abstract, use old slot but it is still empty
+                     *              static : error if any overridden method, doesn't need a slot
+                     *          static new : ignore any overridden method, doesn't need a slot
+                     *             virtual : error if any overridden method, alloc new slot and fill it in
+                     *         virtual new : ignore any overridden method, alloc new slot and fill it in
+                     */
+                    foreach(TokenDeclVar declFunc in sdtClass.members)
+                    {
+                        if(declFunc.retType == null)
+                            continue;
+                        curDeclFunc = declFunc;
+
+                        /*
+                         * See if there is a method in an extended class that this method overshadows.
+                         * If so, check for various conflicts.
+                         * In any case, SDT_NEW on our method means to ignore any overshadowed method.
+                         */
+                        string declLongName = sdtClass.longName.val + "." + declFunc.funcNameSig.val;
+                        uint declFlags = declFunc.sdtFlags;
+                        TokenDeclVar overridden = null;
+                        if((declFlags & ScriptReduce.SDT_NEW) == 0)
+                        {
+                            for(TokenDeclSDTypeClass sdtd = extends; sdtd != null; sdtd = sdtd.extends)
+                            {
+                                overridden = FindExactWithRet(sdtd.members, declFunc.name, declFunc.retType, declFunc.argDecl.types);
+                                if(overridden != null)
+                                    break;
+                            }
+                        }
+                        if(overridden != null)
+                            do
+                            {
+                                string overLongName = overridden.sdtClass.longName.val;
+                                uint overFlags = overridden.sdtFlags;
+
+                                /*
+                                 * See if overridden method allows itself to be overridden.
+                                 */
+                                if((overFlags & ScriptReduce.SDT_ABSTRACT) != 0)
+                                {
+                                    if((declFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_OVERRIDE)) == 0)
+                                    {
+                                        ErrorMsg(declFunc, declLongName + " overshadows abstract " + overLongName + " but is not marked abstract, new or override");
+                                        break;
+                                    }
+                                }
+                                else if((overFlags & ScriptReduce.SDT_FINAL) != 0)
+                                {
+                                    ErrorMsg(declFunc, declLongName + " overshadows final " + overLongName + " but is not marked new");
+                                }
+                                else if((overFlags & (ScriptReduce.SDT_OVERRIDE | ScriptReduce.SDT_VIRTUAL)) != 0)
+                                {
+                                    if((declFlags & (ScriptReduce.SDT_NEW | ScriptReduce.SDT_OVERRIDE)) == 0)
+                                    {
+                                        ErrorMsg(declFunc, declLongName + " overshadows virtual " + overLongName + " but is not marked new or override");
+                                        break;
+                                    }
+                                }
+                                else
+                                {
+                                    ErrorMsg(declFunc, declLongName + " overshadows non-virtual " + overLongName + " but is not marked new");
+                                    break;
+                                }
+
+                                /*
+                                 * See if our method is capable of overriding the other method.
+                                 */
+                                if((declFlags & ScriptReduce.SDT_ABSTRACT) != 0)
+                                {
+                                    if((overFlags & ScriptReduce.SDT_ABSTRACT) == 0)
+                                    {
+                                        ErrorMsg(declFunc, declLongName + " abstract overshadows non-abstract " + overLongName + " but is not marked new");
+                                        break;
+                                    }
+                                }
+                                else if((declFlags & ScriptReduce.SDT_OVERRIDE) != 0)
+                                {
+                                    if((overFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_OVERRIDE | ScriptReduce.SDT_VIRTUAL)) == 0)
+                                    {
+                                        ErrorMsg(declFunc, declLongName + " override overshadows non-abstract/non-virtual " + overLongName);
+                                        break;
+                                    }
+                                }
+                                else
+                                {
+                                    ErrorMsg(declFunc, declLongName + " overshadows " + overLongName + " but is not marked new");
+                                    break;
+                                }
+                            } while(false);
+
+                        /*
+                         * Now we can assign it a vtable slot if it needs one (ie, it is virtual).
+                         */
+                        declFunc.vTableIndex = -1;
+                        if(overridden != null)
+                        {
+                            declFunc.vTableIndex = overridden.vTableIndex;
+                        }
+                        else if((declFlags & ScriptReduce.SDT_OVERRIDE) != 0)
+                        {
+                            ErrorMsg(declFunc, declLongName + " marked override but nothing matching found that it overrides");
+                        }
+                        if((declFlags & (ScriptReduce.SDT_ABSTRACT | ScriptReduce.SDT_VIRTUAL)) != 0)
+                        {
+                            declFunc.vTableIndex = sdtClass.numVirtFuncs++;
+                        }
+                    }
+                    curDeclFunc = null;
+
+                    /*
+                     * ... and assign implemented interface slots.
+                     * Note that our implementations of a given interface is completely independent of any 
+                     * rootward class's implementation of that same interface.
+                     */
+                    int nIFaces = sdtClass.numInterfaces + sdtClass.implements.Count;
+                    sdtClass.iFaces = new TokenDeclSDTypeInterface[nIFaces];
+                    sdtClass.iImplFunc = new TokenDeclVar[nIFaces][];
+                    for(int i = 0; i < sdtClass.numInterfaces; i++)
+                    {
+                        sdtClass.iFaces[i] = extends.iFaces[i];
+                        sdtClass.iImplFunc[i] = extends.iImplFunc[i];
+                    }
+
+                    foreach(TokenDeclSDTypeInterface intf in sdtClass.implements)
+                    {
+                        int i = sdtClass.numInterfaces++;
+                        sdtClass.iFaces[i] = intf;
+                        sdtClass.intfIndices.Add(intf.longName.val, i);
+                        int nMeths = 0;
+                        foreach(TokenDeclVar m in intf.methsNProps)
+                        {
+                            if((m.getProp == null) && (m.setProp == null))
+                                nMeths++;
+                        }
+                        sdtClass.iImplFunc[i] = new TokenDeclVar[nMeths];
+                    }
+
+                    foreach(TokenDeclVar classMeth in sdtClass.members)
+                    {
+                        if(classMeth.retType == null)
+                            continue;
+                        curDeclFunc = classMeth;
+                        for(TokenIntfImpl intfImpl = classMeth.implements; intfImpl != null; intfImpl = (TokenIntfImpl)intfImpl.nextToken)
+                        {
+
+                            /*
+                             * One of the class methods implements an interface method.
+                             * Try to find the interface method that is implemented and verify its signature.
+                             */
+                            TokenDeclSDTypeInterface intfType = intfImpl.intfType.decl;
+                            TokenDeclVar intfMeth = FindExactWithRet(intfType.methsNProps, intfImpl.methName, classMeth.retType, classMeth.argDecl.types);
+                            if(intfMeth == null)
+                            {
+                                ErrorMsg(intfImpl, "interface does not define method " + intfImpl.methName.val + classMeth.argDecl.GetArgSig());
+                                continue;
+                            }
+
+                            /*
+                             * See if this class was declared to implement that interface.
+                             */
+                            bool found = false;
+                            foreach(TokenDeclSDTypeInterface intf in sdtClass.implements)
+                            {
+                                if(intf == intfType)
+                                {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if(!found)
+                            {
+                                ErrorMsg(intfImpl, "class not declared to implement " + intfType.longName.val);
+                                continue;
+                            }
+
+                            /*
+                             * Get index in iFaces[] and iImplFunc[] arrays.
+                             * Start scanning from the end in case one of our rootward classes also implements the interface.
+                             * We should always be successful because we know by now that this class implements the interface.
+                             */
+                            int i;
+                            for(i = sdtClass.numInterfaces; --i >= 0;)
+                            {
+                                if(sdtClass.iFaces[i] == intfType)
+                                    break;
+                            }
+
+                            /*
+                             * Now remember which of the class methods implements that interface method.
+                             */
+                            int j = intfMeth.vTableIndex;
+                            if(sdtClass.iImplFunc[i][j] != null)
+                            {
+                                ErrorMsg(intfImpl, "also implemented by " + sdtClass.iImplFunc[i][j].funcNameSig.val);
+                                continue;
+                            }
+                            sdtClass.iImplFunc[i][j] = classMeth;
+                        }
+                    }
+                    curDeclFunc = null;
+
+                    /*
+                     * Now make sure this class implements all methods for all declared interfaces.
+                     */
+                    for(int i = sdtClass.numInterfaces - sdtClass.implements.Count; i < sdtClass.numInterfaces; i++)
+                    {
+                        TokenDeclVar[] implementations = sdtClass.iImplFunc[i];
+                        for(int j = implementations.Length; --j >= 0;)
+                        {
+                            if(implementations[j] == null)
+                            {
+                                TokenDeclSDTypeInterface intf = sdtClass.iFaces[i];
+                                TokenDeclVar meth = null;
+                                foreach(TokenDeclVar im in intf.methsNProps)
+                                {
+                                    if(im.vTableIndex == j)
+                                    {
+                                        meth = im;
+                                        break;
+                                    }
+                                }
+                                ErrorMsg(sdtClass, "does not implement " + intf.longName.val + "." + meth.funcNameSig.val);
+                            }
+                        }
+                    }
+
+                    /*
+                     * All slots for this class have been assigned.
+                     */
+                    sdtClass.slotsAssigned = true;
+                    didOne = true;
+                }
+            } while(didOne);
+
+            /*
+             * Compute final values for all variables/fields declared as 'constant'.
+             * Note that there may be forward references.
+             */
+            do
+            {
+                didOne = false;
+                foreach(TokenDeclVar tdv in tokenScript.variablesStack)
+                {
+                    if(tdv.constant && !(tdv.init is TokenRValConst))
+                    {
+                        tdv.init = tdv.init.TryComputeConstant(LookupInitConstants, ref didOne);
+                    }
+                }
+                foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+                {
+                    if(!(sdType is TokenDeclSDTypeClass))
+                        continue;
+                    currentSDTClass = (TokenDeclSDTypeClass)sdType;
+                    foreach(TokenDeclVar tdv in currentSDTClass.members)
+                    {
+                        if(tdv.constant && !(tdv.init is TokenRValConst))
+                        {
+                            tdv.init = tdv.init.TryComputeConstant(LookupInitConstants, ref didOne);
+                        }
+                    }
+                }
+                currentSDTClass = null;
+            } while(didOne);
+
+            /*
+             * Now we should be able to assign all those constants their type and location.
+             */
+            foreach(TokenDeclVar tdv in tokenScript.variablesStack)
+            {
+                if(tdv.constant)
+                {
+                    if(tdv.init is TokenRValConst)
+                    {
+                        TokenRValConst rvc = (TokenRValConst)tdv.init;
+                        tdv.type = rvc.tokType;
+                        tdv.location = rvc.GetCompValu();
+                    }
+                    else
+                    {
+                        ErrorMsg(tdv, "value is not constant");
+                    }
+                }
+            }
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                if(!(sdType is TokenDeclSDTypeClass))
+                    continue;
+                currentSDTClass = (TokenDeclSDTypeClass)sdType;
+                foreach(TokenDeclVar tdv in currentSDTClass.members)
+                {
+                    if(tdv.constant)
+                    {
+                        if(tdv.init is TokenRValConst)
+                        {
+                            TokenRValConst rvc = (TokenRValConst)tdv.init;
+                            tdv.type = rvc.tokType;
+                            tdv.location = rvc.GetCompValu();
+                        }
+                        else
+                        {
+                            ErrorMsg(tdv, "value is not constant");
+                        }
+                    }
+                }
+            }
+            currentSDTClass = null;
+
+            /*
+             * For all classes that define all the methods needed for the class, ie, they aren't abstract,
+             * define a static class.$new() method with same args as the $ctor(s).  This will allow the
+             * class to be instantiated via the new operator.
+             */
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                if(!(sdType is TokenDeclSDTypeClass))
+                    continue;
+                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+
+                /*
+                 * See if the class as it stands would be able to fill every slot of its vtable.
+                 */
+                bool[] filled = new bool[sdtClass.numVirtFuncs];
+                int numFilled = 0;
+                for(TokenDeclSDTypeClass sdtc = sdtClass; sdtc != null; sdtc = sdtc.extends)
+                {
+                    foreach(TokenDeclVar tdf in sdtc.members)
+                    {
+                        if((tdf.retType != null) && (tdf.vTableIndex >= 0) && ((tdf.sdtFlags & ScriptReduce.SDT_ABSTRACT) == 0))
+                        {
+                            if(!filled[tdf.vTableIndex])
+                            {
+                                filled[tdf.vTableIndex] = true;
+                                numFilled++;
+                            }
+                        }
+                    }
+                }
+
+                /*
+                 * If so, define a static class.$new() method for every constructor defined for the class.
+                 * Give it the same access (private/protected/public) as the script declared for the constructor.
+                 * Note that the reducer made sure there is at least a default constructor for every class.
+                 */
+                if(numFilled >= sdtClass.numVirtFuncs)
+                {
+                    List<TokenDeclVar> newobjDeclFuncs = new List<TokenDeclVar>();
+                    foreach(TokenDeclVar ctorDeclFunc in sdtClass.members)
+                    {
+                        if((ctorDeclFunc.funcNameSig != null) && ctorDeclFunc.funcNameSig.val.StartsWith("$ctor("))
+                        {
+                            TokenDeclVar newobjDeclFunc = DefineNewobjFunc(ctorDeclFunc);
+                            newobjDeclFuncs.Add(newobjDeclFunc);
+                        }
+                    }
+                    foreach(TokenDeclVar newobjDeclFunc in newobjDeclFuncs)
+                    {
+                        sdtClass.members.AddEntry(newobjDeclFunc);
+                    }
+                }
+            }
+
+            /*
+             * Write fixed portion of object file.
+             */
+            objFileWriter.Write(OBJECT_CODE_MAGIC.ToCharArray());
+            objFileWriter.Write(COMPILED_VERSION_VALUE);
+            objFileWriter.Write(sourceHash);
+            glblSizes.WriteToFile(objFileWriter);
+
+            objFileWriter.Write(nStates);
+            for(int i = 0; i < nStates; i++)
+            {
+                objFileWriter.Write(stateNames[i]);
+            }
+
+            /*
+             * For debugging, we also write out global variable array slot assignments.
+             */
+            foreach(TokenDeclVar declVar in tokenScript.variablesStack)
+            {
+                if(declVar.retType == null)
+                {
+                    WriteOutGblAssignment("", declVar);
+                }
+            }
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                if(!(sdType is TokenDeclSDTypeClass))
+                    continue;
+                TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+                foreach(TokenDeclVar declVar in sdtClass.members)
+                {
+                    if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+                    {
+                        WriteOutGblAssignment(sdtClass.longName.val + ".", declVar);
+                    }
+                }
+            }
+            objFileWriter.Write("");
+
+            /*
+             * Write out script-defined types.
+             */
+            foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+            {
+                objFileWriter.Write(sdType.longName.val);
+                sdType.WriteToFile(objFileWriter);
+            }
+            objFileWriter.Write("");
+
+            /*
+             * Output function headers then bodies.
+             * Do all headers first in case bodies do forward references.
+             * Do both global functions, script-defined class static methods and 
+             * script-defined instance methods, as we handle the differences
+             * during compilation of the functions/methods themselves.
+             */
+            for(int pass = 0; pass < 2; pass++)
+            {
+                foreach(TokenDeclVar declFunc in tokenScript.variablesStack)
+                {
+                    if(declFunc.retType != null)
+                    {
+                        if(pass == 0)
+                            GenerateMethodHeader(declFunc);
+                        else
+                            GenerateMethodBody(declFunc);
+                    }
+                }
+                foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+                {
+                    if(sdType is TokenDeclSDTypeClass)
+                    {
+                        TokenDeclSDTypeClass sdtClass = (TokenDeclSDTypeClass)sdType;
+                        foreach(TokenDeclVar declFunc in sdtClass.members)
+                        {
+                            if((declFunc.retType != null) && ((declFunc.sdtFlags & ScriptReduce.SDT_ABSTRACT) == 0))
+                            {
+                                if(pass == 0)
+                                    GenerateMethodHeader(declFunc);
+                                else
+                                    GenerateMethodBody(declFunc);
+                            }
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Output default state event handler functions.
+             * Each event handler is a private static method named 'default <eventname>'.
+             * Splice in a default state_entry() handler if none defined so we can init global vars.
+             */
+            TokenDeclVar defaultStateEntry = null;
+            for(defaultStateEntry = tokenScript.defaultState.body.eventFuncs;
+                 defaultStateEntry != null;
+                 defaultStateEntry = (TokenDeclVar)defaultStateEntry.nextToken)
+            {
+                if(defaultStateEntry.funcNameSig.val == "state_entry()")
+                    break;
+            }
+            if(defaultStateEntry == null)
+            {
+                defaultStateEntry = new TokenDeclVar(tokenScript.defaultState.body, null, tokenScript);
+                defaultStateEntry.name = new TokenName(tokenScript.defaultState.body, "state_entry");
+                defaultStateEntry.retType = new TokenTypeVoid(tokenScript.defaultState.body);
+                defaultStateEntry.argDecl = new TokenArgDecl(tokenScript.defaultState.body);
+                defaultStateEntry.body = new TokenStmtBlock(tokenScript.defaultState.body);
+                defaultStateEntry.body.function = defaultStateEntry;
+
+                defaultStateEntry.nextToken = tokenScript.defaultState.body.eventFuncs;
+                tokenScript.defaultState.body.eventFuncs = defaultStateEntry;
+            }
+            GenerateStateEventHandlers("default", tokenScript.defaultState.body);
+
+            /*
+             * Output script-defined state event handler methods.
+             * Each event handler is a private static method named <statename> <eventname>
+             */
+            foreach(KeyValuePair<string, TokenDeclState> kvp in tokenScript.states)
+            {
+                TokenDeclState declState = kvp.Value;
+                GenerateStateEventHandlers(declState.name.val, declState.body);
+            }
+
+            ScriptObjWriter.TheEnd(objFileWriter);
+        }
+
+        /**
+         * @brief Write out what slot was assigned for a global or sdtclass static variable.
+         *        Constants, functions, instance fields, methods, properties do not have slots in the global variables arrays.
+         */
+        private void WriteOutGblAssignment(string pfx, TokenDeclVar declVar)
+        {
+            if(!declVar.constant && (declVar.retType == null) && (declVar.getProp == null) && (declVar.setProp == null))
+            {
+                objFileWriter.Write(pfx + declVar.name.val);    // string
+                objFileWriter.Write(declVar.vTableArray.Name);  // string
+                objFileWriter.Write(declVar.vTableIndex);       // int
+            }
+        }
+
+        /**
+         * @brief generate event handler code
+         * Writes out a function definition for each state handler
+         * named <statename> <eventname>
+         *
+         * However, each has just 'XMRInstance __sw' as its single argument
+         * and each of its user-visible argments is extracted from __sw.ehArgs[].
+         *
+         * So we end up generating something like this:
+         *
+         *   private static void <statename> <eventname>(XMRInstance __sw)
+         *   {
+         *      <typeArg0> <nameArg0> = (<typeArg0>)__sw.ehArgs[0];
+         *      <typeArg1> <nameArg1> = (<typeArg1>)__sw.ehArgs[1];
+         *
+         *      ... script code ...
+         *   }
+         *
+         * The continuations code assumes there will be no references to ehArgs[]
+         * after the first call to CheckRun() as CheckRun() makes no attempt to
+         * serialize the ehArgs[] array, as doing so would be redundant.  Any values
+         * from ehArgs[] that are being used will be in local stack variables and
+         * thus preserved that way.
+         */
+        private void GenerateStateEventHandlers(string statename, TokenStateBody body)
+        {
+            Dictionary<string, TokenDeclVar> statehandlers = new Dictionary<string, TokenDeclVar>();
+            for(Token t = body.eventFuncs; t != null; t = t.nextToken)
+            {
+                TokenDeclVar tdv = (TokenDeclVar)t;
+                string eventname = tdv.GetSimpleName();
+                if(statehandlers.ContainsKey(eventname))
+                {
+                    ErrorMsg(tdv, "event handler " + eventname + " already defined for state " + statename);
+                }
+                else
+                {
+                    statehandlers.Add(eventname, tdv);
+                    GenerateEventHandler(statename, tdv);
+                }
+            }
+        }
+
+        private void GenerateEventHandler(string statename, TokenDeclVar declFunc)
+        {
+            string eventname = declFunc.GetSimpleName();
+            TokenArgDecl argDecl = declFunc.argDecl;
+
+            /*
+             * Make sure event handler name is valid and that number and type of arguments is correct.
+             * Apparently some scripts exist with fewer than correct number of args in their declaration 
+             * so allow for that.  It is ok because the handlers are called with the arguments in an
+             * object[] array, and we just won't access the missing argments in the vector.  But the 
+             * specified types must match one of the prototypes in legalEventHandlers.
+             */
+            TokenDeclVar protoDeclFunc = legalEventHandlers.FindExact(eventname, argDecl.types);
+            if(protoDeclFunc == null)
+            {
+                ErrorMsg(declFunc, "unknown event handler " + eventname + argDecl.GetArgSig());
+                return;
+            }
+
+            /*
+             * Output function header.
+             * They just have the XMRInstAbstract pointer as the one argument.
+             */
+            string functionName = statename + " " + eventname;
+            _ilGen = new ScriptObjWriter(tokenScript,
+                                          functionName,
+                                          typeof(void),
+                                          instanceTypeArg,
+                                          instanceNameArg,
+                                          objFileWriter);
+            StartFunctionBody(declFunc);
+
+            /*
+             * Create a temp to hold XMRInstanceSuperType version of arg 0.
+             */
+            instancePointer = ilGen.DeclareLocal(xmrInstSuperType, "__xmrinst");
+            ilGen.Emit(declFunc, OpCodes.Ldarg_0);
+            ilGen.Emit(declFunc, OpCodes.Castclass, xmrInstSuperType);
+            ilGen.Emit(declFunc, OpCodes.Stloc, instancePointer);
+
+            /*
+             * Output args as variable definitions and initialize each from __sw.ehArgs[].
+             * If the script writer goofed, the typecast will complain.
+             */
+            int nArgs = argDecl.vars.Length;
+            for(int i = 0; i < nArgs; i++)
+            {
+
+                /*
+                 * Say that the argument variable is going to be located in a local var.
+                 */
+                TokenDeclVar argVar = argDecl.vars[i];
+                TokenType argTokType = argVar.type;
+                CompValuLocalVar local = new CompValuLocalVar(argTokType, argVar.name.val, this);
+                argVar.location = local;
+
+                /*
+                 * Copy from the ehArgs[i] element to the temp var.
+                 * Cast as needed, there is a lot of craziness like OpenMetaverse.Quaternion.
+                 */
+                local.PopPre(this, argVar.name);
+                PushXMRInst();                                          // instance
+                ilGen.Emit(declFunc, OpCodes.Ldfld, ehArgsFieldInfo);   // instance.ehArgs (array of objects)
+                ilGen.Emit(declFunc, OpCodes.Ldc_I4, i);                // array index = i
+                ilGen.Emit(declFunc, OpCodes.Ldelem, typeof(object));  // select the argument we want
+                TokenType stkTokType = tokenTypeObj;                     // stack has a type 'object' on it now
+                Type argSysType = argTokType.ToSysType();               // this is the type the script expects
+                if(argSysType == typeof(double))
+                {                // LSL_Float/double -> double
+                    ilGen.Emit(declFunc, OpCodes.Call, ehArgUnwrapFloat);
+                    stkTokType = tokenTypeFlt;                       // stack has a type 'double' on it now
+                }
+                if(argSysType == typeof(int))
+                {                        // LSL_Integer/int -> int
+                    ilGen.Emit(declFunc, OpCodes.Call, ehArgUnwrapInteger);
+                    stkTokType = tokenTypeInt;                       // stack has a type 'int' on it now
+                }
+                if(argSysType == typeof(LSL_List))
+                {                   // LSL_List -> LSL_List
+                    TypeCast.CastTopOfStack(this, argVar.name, stkTokType, argTokType, true);
+                    stkTokType = argTokType;                         // stack has a type 'LSL_List' on it now
+                }
+                if(argSysType == typeof(LSL_Rotation))
+                {               // OpenMetaverse.Quaternion/LSL_Rotation -> LSL_Rotation
+                    ilGen.Emit(declFunc, OpCodes.Call, ehArgUnwrapRotation);
+                    stkTokType = tokenTypeRot;                       // stack has a type 'LSL_Rotation' on it now
+                }
+                if(argSysType == typeof(string))
+                {                     // LSL_Key/LSL_String/string -> string
+                    ilGen.Emit(declFunc, OpCodes.Call, ehArgUnwrapString);
+                    stkTokType = tokenTypeStr;                       // stack has a type 'string' on it now
+                }
+                if(argSysType == typeof(LSL_Vector))
+                {                 // OpenMetaverse.Vector3/LSL_Vector -> LSL_Vector
+                    ilGen.Emit(declFunc, OpCodes.Call, ehArgUnwrapVector);
+                    stkTokType = tokenTypeVec;                       // stack has a type 'LSL_Vector' on it now
+                }
+                local.PopPost(this, argVar.name, stkTokType);           // pop stack type into argtype
+            }
+
+            /*
+             * Output code for the statements and clean up.
+             */
+            GenerateFuncBody();
+        }
+
+        /**
+         * @brief generate header for an arbitrary script-defined global function.
+         * @param declFunc = function being defined
+         */
+        private void GenerateMethodHeader(TokenDeclVar declFunc)
+        {
+            curDeclFunc = declFunc;
+
+            /*
+             * Make up array of all argument types as seen by the code generator.
+             * We splice in XMRInstanceSuperType or XMRSDTypeClObj for the first 
+             * arg as the function itself is static, followed by script-visible
+             * arg types.
+             */
+            TokenArgDecl argDecl = declFunc.argDecl;
+            int nArgs = argDecl.vars.Length;
+            Type[] argTypes = new Type[nArgs + 1];
+            string[] argNames = new string[nArgs + 1];
+            if(IsSDTInstMethod())
+            {
+                argTypes[0] = typeof(XMRSDTypeClObj);
+                argNames[0] = "$sdtthis";
+            }
+            else
+            {
+                argTypes[0] = xmrInstSuperType;
+                argNames[0] = "$xmrthis";
+            }
+            for(int i = 0; i < nArgs; i++)
+            {
+                argTypes[i + 1] = argDecl.vars[i].type.ToSysType();
+                argNames[i + 1] = argDecl.vars[i].name.val;
+            }
+
+            /*
+             * Set up entrypoint.
+             */
+            string objCodeName = declFunc.GetObjCodeName();
+            declFunc.ilGen = new ScriptObjWriter(tokenScript,
+                                                  objCodeName,
+                                                  declFunc.retType.ToSysType(),
+                                                  argTypes,
+                                                  argNames,
+                                                  objFileWriter);
+
+            /*
+             * This says how to generate a call to the function and to get a delegate.
+             */
+            declFunc.location = new CompValuGlobalMeth(declFunc);
+
+            curDeclFunc = null;
+        }
+
+        /**
+         * @brief generate code for an arbitrary script-defined function.
+         * @param name = name of the function
+         * @param argDecl = argument declarations
+         * @param body = function's code body
+         */
+        private void GenerateMethodBody(TokenDeclVar declFunc)
+        {
+            /*
+             * Set up code generator for the function's contents.
+             */
+            _ilGen = declFunc.ilGen;
+            StartFunctionBody(declFunc);
+
+            /*
+             * Create a temp to hold XMRInstanceSuperType version of arg 0.
+             * For most functions, arg 0 is already XMRInstanceSuperType.
+             * But for script-defined class instance methods, arg 0 holds
+             * the XMRSDTypeClObj pointer and so we read the XMRInstAbstract
+             * pointer from its XMRSDTypeClObj.xmrInst field then cast it to
+             * XMRInstanceSuperType.
+             */
+            if(IsSDTInstMethod())
+            {
+                instancePointer = ilGen.DeclareLocal(xmrInstSuperType, "__xmrinst");
+                ilGen.Emit(declFunc, OpCodes.Ldarg_0);
+                ilGen.Emit(declFunc, OpCodes.Ldfld, sdtXMRInstFieldInfo);
+                ilGen.Emit(declFunc, OpCodes.Castclass, xmrInstSuperType);
+                ilGen.Emit(declFunc, OpCodes.Stloc, instancePointer);
+            }
+
+            /*
+             * Define location of all script-level arguments so script body can access them.
+             * The argument indices need to have +1 added to them because XMRInstance or 
+             * XMRSDTypeClObj is spliced in at arg 0.
+             */
+            TokenArgDecl argDecl = declFunc.argDecl;
+            int nArgs = argDecl.vars.Length;
+            for(int i = 0; i < nArgs; i++)
+            {
+                TokenDeclVar argVar = argDecl.vars[i];
+                argVar.location = new CompValuArg(argVar.type, i + 1);
+            }
+
+            /*
+             * Output code for the statements and clean up.
+             */
+            GenerateFuncBody();
+        }
+
+        private void StartFunctionBody(TokenDeclVar declFunc)
+        {
+            /*
+             * Start current function being processed.
+             * Set 'mightGetHere' as the code at the top is always executed.
+             */
+            instancePointer = null;
+            mightGetHere = true;
+            curBreakTarg = null;
+            curContTarg = null;
+            curDeclFunc = declFunc;
+
+            /*
+             * Start generating code.
+             */
+            ((ScriptObjWriter)ilGen).BegMethod();
+        }
+
+        /**
+         * @brief Define function for a script-defined type's <typename>.$new(<argsig>) method.
+         *        See GenerateStmtNewobj() for more info.
+         */
+        private TokenDeclVar DefineNewobjFunc(TokenDeclVar ctorDeclFunc)
+        {
+            /*
+             * Set up 'static classname $new(params-same-as-ctor) { }'.
+             */
+            TokenDeclVar newobjDeclFunc = new TokenDeclVar(ctorDeclFunc, null, tokenScript);
+            newobjDeclFunc.name = new TokenName(newobjDeclFunc, "$new");
+            newobjDeclFunc.retType = ctorDeclFunc.sdtClass.MakeRefToken(newobjDeclFunc);
+            newobjDeclFunc.argDecl = ctorDeclFunc.argDecl;
+            newobjDeclFunc.sdtClass = ctorDeclFunc.sdtClass;
+            newobjDeclFunc.sdtFlags = ScriptReduce.SDT_STATIC | ctorDeclFunc.sdtFlags;
+
+            /*
+             * Declare local variable named '$objptr' in a frame just under 
+             * what the '$new(...)' function's arguments are declared in.
+             */
+            TokenDeclVar objptrVar = new TokenDeclVar(newobjDeclFunc, newobjDeclFunc, tokenScript);
+            objptrVar.type = newobjDeclFunc.retType;
+            objptrVar.name = new TokenName(newobjDeclFunc, "$objptr");
+            VarDict newFrame = new VarDict(false);
+            newFrame.outerVarDict = ctorDeclFunc.argDecl.varDict;
+            newFrame.AddEntry(objptrVar);
+
+            /*
+             * Set up '$objptr.$ctor'
+             */
+            TokenLValName objptrLValName = new TokenLValName(objptrVar.name, newFrame);
+            // ref a var by giving its name
+            TokenLValIField objptrDotCtor = new TokenLValIField(newobjDeclFunc);  // an instance member reference
+            objptrDotCtor.baseRVal = objptrLValName;                        // '$objptr'
+            objptrDotCtor.fieldName = ctorDeclFunc.name;                     // '.' '$ctor'
+
+            /*
+             * Set up '$objptr.$ctor(arglist)' call for use in the '$new(...)' body.
+             * Copy the arglist from the constructor declaration so triviality 
+             * processing will pick the correct overloaded constructor.
+             */
+            TokenRValCall callCtorRVal = new TokenRValCall(newobjDeclFunc);   // doing a call of some sort
+            callCtorRVal.meth = objptrDotCtor;                        // calling $objptr.$ctor()
+            TokenDeclVar[] argList = newobjDeclFunc.argDecl.vars;          // get args $new() was declared with
+            callCtorRVal.nArgs = argList.Length;                       // ...that is nArgs we are passing to $objptr.$ctor()
+            for(int i = argList.Length; --i >= 0;)
+            {
+                TokenDeclVar arg = argList[i];                    // find out about one of the args
+                TokenLValName argLValName = new TokenLValName(arg.name, ctorDeclFunc.argDecl.varDict);
+                // pass arg of that name to $objptr.$ctor()
+                argLValName.nextToken = callCtorRVal.args;             // link to list of args passed to $objptr.$ctor()
+                callCtorRVal.args = argLValName;
+            }
+
+            /*
+             * Set up a funky call to the constructor for the code body.
+             * This will let code generator know there is some craziness.
+             * See GenerateStmtNewobj().
+             *
+             * This is in essence:
+             *    {
+             *        classname $objptr = newobj (classname);
+             *        $objptr.$ctor (...);
+             *        return $objptr;
+             *    }
+             */
+            TokenStmtNewobj newobjStmtBody = new TokenStmtNewobj(ctorDeclFunc);
+            newobjStmtBody.objptrVar = objptrVar;
+            newobjStmtBody.rValCall = callCtorRVal;
+            TokenStmtBlock newobjBody = new TokenStmtBlock(ctorDeclFunc);
+            newobjBody.statements = newobjStmtBody;
+
+            /*
+             * Link that code as the body of the function.
+             */
+            newobjDeclFunc.body = newobjBody;
+
+            /*
+             * Say the function calls '$objptr.$ctor(arglist)' so we will inherit ctor's triviality.
+             */
+            newobjDeclFunc.unknownTrivialityCalls.AddLast(callCtorRVal);
+            return newobjDeclFunc;
+        }
+
+        private class TokenStmtNewobj: TokenStmt
+        {
+            public TokenDeclVar objptrVar;
+            public TokenRValCall rValCall;
+            public TokenStmtNewobj(Token original) : base(original) { }
+        }
+
+        /**
+         * @brief Output function body (either event handler or script-defined method).
+         */
+        private void GenerateFuncBody()
+        {
+            /*
+             * We want to know if the function's code is trivial, ie,
+             * if it doesn't have anything that might be an infinite 
+             * loop and that is doesn't call anything that might have 
+             * an infinite loop.  If it is, we don't need any CheckRun()
+             * stuff or any of the frame save/restore stuff.
+             */
+            bool isTrivial = curDeclFunc.IsFuncTrivial(this);
+
+            /*
+             * Clear list of all call labels.
+             * A call label is inserted just before every call that can possibly
+             * call CheckRun(), including any direct calls to CheckRun().
+             * Then, when restoring stack, we can just switch to this label to
+             * resume at the correct spot.
+             */
+            actCallLabels.Clear();
+            allCallLabels.Clear();
+            openCallLabel = null;
+
+            /*
+             * Alloc stack space for local vars.
+             */
+            int stackframesize = AllocLocalVarStackSpace();
+
+            /*
+             * Include argument variables in stack space for this frame.
+             */
+            foreach(TokenType tokType in curDeclFunc.argDecl.types)
+            {
+                stackframesize += LocalVarStackSize(tokType);
+            }
+
+            /*
+             * Any return statements inside function body jump to this label
+             * after putting return value in __retval.
+             */
+            retLabel = ilGen.DefineLabel("__retlbl");
+            retValue = null;
+            if(!(curDeclFunc.retType is TokenTypeVoid))
+            {
+                retValue = ilGen.DeclareLocal(curDeclFunc.retType.ToSysType(), "__retval");
+            }
+
+            /*
+             * Output:
+             *    int __mainCallNo = -1;
+             *    instance.m_StackLeft -= stackframesize;
+             *    try {
+             *        if (instance.callMode != CallMode_NORMAL) goto __cmRestore;
+             */
+            actCallNo = null;
+            ScriptMyLabel cmRestore = null;
+            if(!isTrivial)
+            {
+                actCallNo = ilGen.DeclareLocal(typeof(int), "__mainCallNo");
+                SetCallNo(curDeclFunc, actCallNo, -1);
+                PushXMRInst();
+                ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldfld, stackLeftFieldInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, stackframesize);
+                ilGen.Emit(curDeclFunc, OpCodes.Sub);
+                ilGen.Emit(curDeclFunc, OpCodes.Stfld, stackLeftFieldInfo);
+                cmRestore = ilGen.DefineLabel("__cmRestore");
+                ilGen.BeginExceptionBlock();
+                PushXMRInst();
+                ilGen.Emit(curDeclFunc, OpCodes.Ldfld, ScriptCodeGen.callModeFieldInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_NORMAL);
+                ilGen.Emit(curDeclFunc, OpCodes.Bne_Un, cmRestore);
+            }
+
+            /*
+             * Splice in the code optimizer for the body of the function.
+             */
+            ScriptCollector collector = new ScriptCollector((ScriptObjWriter)ilGen);
+            _ilGen = collector;
+
+            /*
+             * If this is the default state_entry() handler, output code to set all global
+             * variables to their initial values.  Note that every script must have a
+             * default state_entry() handler, we provide one if the script doesn't explicitly
+             * define one.
+             */
+            string methname = ilGen.methName;
+            if(methname == "default state_entry")
+            {
+
+                // if (!doGblInit) goto skipGblInit;
+                ScriptMyLabel skipGblInitLabel = ilGen.DefineLabel("__skipGblInit");
+                PushXMRInst();                                  // instance
+                ilGen.Emit(curDeclFunc, OpCodes.Ldfld, doGblInitFieldInfo);  // instance.doGblInit
+                ilGen.Emit(curDeclFunc, OpCodes.Brfalse, skipGblInitLabel);
+
+                // $globalvarinit();
+                TokenDeclVar gviFunc = tokenScript.globalVarInit;
+                if(gviFunc.body.statements != null)
+                {
+                    gviFunc.location.CallPre(this, gviFunc);
+                    gviFunc.location.CallPost(this, gviFunc);
+                }
+
+                // various $staticfieldinit();
+                foreach(TokenDeclSDType sdType in tokenScript.sdSrcTypesValues)
+                {
+                    if(sdType is TokenDeclSDTypeClass)
+                    {
+                        TokenDeclVar sfiFunc = ((TokenDeclSDTypeClass)sdType).staticFieldInit;
+                        if((sfiFunc != null) && (sfiFunc.body.statements != null))
+                        {
+                            sfiFunc.location.CallPre(this, sfiFunc);
+                            sfiFunc.location.CallPost(this, sfiFunc);
+                        }
+                    }
+                }
+
+                // doGblInit = 0;
+                PushXMRInst();                                  // instance
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4_0);
+                ilGen.Emit(curDeclFunc, OpCodes.Stfld, doGblInitFieldInfo);  // instance.doGblInit
+
+                //skipGblInit:
+                ilGen.MarkLabel(skipGblInitLabel);
+            }
+
+            /*
+             * If this is a script-defined type constructor, call the base constructor and call
+             * this class's $instfieldinit() method to initialize instance fields.
+             */
+            if((curDeclFunc.sdtClass != null) && curDeclFunc.funcNameSig.val.StartsWith("$ctor("))
+            {
+                if(curDeclFunc.baseCtorCall != null)
+                {
+                    GenerateFromRValCall(curDeclFunc.baseCtorCall);
+                }
+                TokenDeclVar ifiFunc = ((TokenDeclSDTypeClass)curDeclFunc.sdtClass).instFieldInit;
+                if(ifiFunc.body.statements != null)
+                {
+                    CompValu thisCompValu = new CompValuArg(ifiFunc.sdtClass.MakeRefToken(ifiFunc), 0);
+                    CompValu ifiFuncLocn = new CompValuInstMember(ifiFunc, thisCompValu, true);
+                    ifiFuncLocn.CallPre(this, ifiFunc);
+                    ifiFuncLocn.CallPost(this, ifiFunc);
+                }
+            }
+
+            /*
+             * See if time to suspend in case they are doing a loop with recursion.
+             */
+            if(!isTrivial)
+                EmitCallCheckRun(curDeclFunc, true);
+
+            /*
+             * Output code body.
+             */
+            GenerateStmtBlock(curDeclFunc.body);
+
+            /*
+             * If code falls through to this point, means they are missing 
+             * a return statement.  And that is legal only if the function 
+             * returns 'void'.
+             */
+            if(mightGetHere)
+            {
+                if(!(curDeclFunc.retType is TokenTypeVoid))
+                {
+                    ErrorMsg(curDeclFunc.body, "missing final return statement");
+                }
+                ilGen.Emit(curDeclFunc, OpCodes.Leave, retLabel);
+            }
+
+            /*
+             * End of the code to be optimized.
+             * Do optimizations then write it all out to object file.
+             * After this, all code gets written directly to object file.
+             * Optimization must be completed before we scan the allCallLabels
+             * list below to look for active locals and temps.
+             */
+            collector.Optimize();
+            _ilGen = collector.WriteOutAll();
+            collector = null;
+
+            /*
+             * Output code to restore stack frame from stream.
+             * It jumps back to the call labels within the function body.
+             */
+            List<ScriptMyLocal> activeTemps = null;
+            if(!isTrivial)
+            {
+
+                /*
+                 * Build list of locals and temps active at all the call labels.
+                 */
+                activeTemps = new List<ScriptMyLocal>();
+                foreach(CallLabel cl in allCallLabels)
+                {
+                    foreach(ScriptMyLocal lcl in cl.callLabel.whereAmI.localsReadBeforeWritten)
+                    {
+                        if(!activeTemps.Contains(lcl))
+                        {
+                            activeTemps.Add(lcl);
+                        }
+                    }
+                }
+
+                /*
+                 * Output code to restore the args, locals and temps then jump to
+                 * the call label that we were interrupted at.
+                 */
+                ilGen.MarkLabel(cmRestore);
+                GenerateFrameRestoreCode(activeTemps);
+            }
+
+            /*
+             * Output epilog that saves stack frame state if CallMode_SAVE.
+             *
+             *   finally {
+             *      instance.m_StackLeft += stackframesize;
+             *      if (instance.callMode != CallMode_SAVE) goto __endFin;
+             *      GenerateFrameCaptureCode();
+             *   __endFin:
+             *   }
+             */
+            ScriptMyLabel endFin = null;
+            if(!isTrivial)
+            {
+                ilGen.BeginFinallyBlock();
+                PushXMRInst();
+                ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldfld, stackLeftFieldInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, stackframesize);
+                ilGen.Emit(curDeclFunc, OpCodes.Add);
+                ilGen.Emit(curDeclFunc, OpCodes.Stfld, stackLeftFieldInfo);
+                endFin = ilGen.DefineLabel("__endFin");
+                PushXMRInst();
+                ilGen.Emit(curDeclFunc, OpCodes.Ldfld, callModeFieldInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
+                ilGen.Emit(curDeclFunc, OpCodes.Bne_Un, endFin);
+                GenerateFrameCaptureCode(activeTemps);
+                ilGen.MarkLabel(endFin);
+                ilGen.Emit(curDeclFunc, OpCodes.Endfinally);
+                ilGen.EndExceptionBlock();
+            }
+
+            /*
+             * Output the 'real' return opcode.
+             */
+            ilGen.MarkLabel(retLabel);
+            if(!(curDeclFunc.retType is TokenTypeVoid))
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, retValue);
+            }
+            ilGen.Emit(curDeclFunc, OpCodes.Ret);
+            retLabel = null;
+            retValue = null;
+
+            /*
+             * No more instructions for this method.
+             */
+            ((ScriptObjWriter)ilGen).EndMethod();
+            _ilGen = null;
+
+            /*
+             * Not generating function code any more.
+             */
+            curBreakTarg = null;
+            curContTarg = null;
+            curDeclFunc = null;
+        }
+
+        /**
+         * @brief Allocate stack space for all local variables, regardless of
+         *        which { } statement block they are actually defined in.
+         * @returns approximate stack frame size
+         */
+        private int AllocLocalVarStackSpace()
+        {
+            int stackframesize = 64;  // RIP, RBX, RBP, R12..R15, one extra
+            foreach(TokenDeclVar localVar in curDeclFunc.localVars)
+            {
+
+                /*
+                 * Skip all 'constant' vars as they were handled by the reducer.
+                 */
+                if(localVar.constant)
+                    continue;
+
+                /*
+                 * Get a stack location for the local variable.
+                 */
+                localVar.location = new CompValuLocalVar(localVar.type, localVar.name.val, this);
+
+                /*
+                 * Stack size for the local variable.
+                 */
+                stackframesize += LocalVarStackSize(localVar.type);
+            }
+            return stackframesize;
+        }
+
+        private static int LocalVarStackSize(TokenType tokType)
+        {
+            Type sysType = tokType.ToSysType();
+            return sysType.IsValueType ? System.Runtime.InteropServices.Marshal.SizeOf(sysType) : 8;
+        }
+
+        /**
+         * @brief Generate code to write all arguments and locals to the capture stack frame.
+         *        This includes temp variables.
+         *        We only need to save what is active at the point of callLabels through because 
+         *        those are the only points we will jump to on restore.  This saves us from saving 
+         *        all the little temp vars we create.
+         * @param activeTemps = list of locals and temps that we care about, ie, which
+         *                      ones get restored by GenerateFrameRestoreCode().
+         */
+        private void GenerateFrameCaptureCode(List<ScriptMyLocal> activeTemps)
+        {
+            /*
+             * Compute total number of slots we need to save stuff.
+             * Assume we need to save all call arguments.
+             */
+            int nSaves = curDeclFunc.argDecl.vars.Length + activeTemps.Count;
+
+            /*
+             * Output code to allocate a stack frame object with an object array.
+             * This also pushes the stack frame object on the instance.stackFrames list.
+             * It returns a pointer to the object array it allocated.
+             */
+            PushXMRInst();
+            ilGen.Emit(curDeclFunc, OpCodes.Ldstr, ilGen.methName);
+            GetCallNo(curDeclFunc, actCallNo);
+            ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, nSaves);
+            ilGen.Emit(curDeclFunc, OpCodes.Call, captureStackFrameMethodInfo);
+
+            if(DEBUG_STACKCAPRES)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Ldstr, ilGen.methName + "*: capture mainCallNo=");
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, actCallNo);
+                ilGen.Emit(curDeclFunc, OpCodes.Box, typeof(int));
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            /*
+             * Copy arg values to object array, boxing as needed.
+             */
+            int i = 0;
+            foreach(TokenDeclVar argVar in curDeclFunc.argDecl.varDict)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, i);
+                argVar.location.PushVal(this, argVar.name, tokenTypeObj);
+                if(DEBUG_STACKCAPRES)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n    arg:" + argVar.name.val + "=");
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                    ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                }
+                ilGen.Emit(curDeclFunc, OpCodes.Stelem_Ref);
+                i++;
+            }
+
+            /*
+             * Copy local and temp values to object array, boxing as needed.
+             */
+            foreach(ScriptMyLocal lcl in activeTemps)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, i++);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, lcl);
+                Type t = lcl.type;
+                if(t == typeof(HeapTrackerList))
+                {
+                    t = HeapTrackerList.GenPush(curDeclFunc, ilGen);
+                }
+                if(t == typeof(HeapTrackerObject))
+                {
+                    t = HeapTrackerObject.GenPush(curDeclFunc, ilGen);
+                }
+                if(t == typeof(HeapTrackerString))
+                {
+                    t = HeapTrackerString.GenPush(curDeclFunc, ilGen);
+                }
+                if(t.IsValueType)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Box, t);
+                }
+                if(DEBUG_STACKCAPRES)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n    lcl:" + lcl.name + "=");
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                    ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                }
+                ilGen.Emit(curDeclFunc, OpCodes.Stelem_Ref);
+            }
+            if(DEBUG_STACKCAPRES)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n");
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            ilGen.Emit(curDeclFunc, OpCodes.Pop);
+        }
+
+        /**
+         * @brief Generate code to restore all arguments and locals from the restore stack frame.
+         *        This includes temp variables.
+         */
+        private void GenerateFrameRestoreCode(List<ScriptMyLocal> activeTemps)
+        {
+            ScriptMyLocal objArray = ilGen.DeclareLocal(typeof(object[]), "__restObjArray");
+
+            /*
+             * Output code to pop stack frame from instance.stackFrames.
+             * It returns a pointer to the object array that contains values to be restored.
+             */
+            PushXMRInst();
+            ilGen.Emit(curDeclFunc, OpCodes.Ldstr, ilGen.methName);
+            ilGen.Emit(curDeclFunc, OpCodes.Ldloca, actCallNo);  // __mainCallNo
+            ilGen.Emit(curDeclFunc, OpCodes.Call, restoreStackFrameMethodInfo);
+            ilGen.Emit(curDeclFunc, OpCodes.Stloc, objArray);
+            if(DEBUG_STACKCAPRES)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Ldstr, ilGen.methName + "*: restore mainCallNo=");
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, actCallNo);
+                ilGen.Emit(curDeclFunc, OpCodes.Box, typeof(int));
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            /*
+             * Restore argument values from object array, unboxing as needed.
+             * Although the caller has restored them to what it called us with, it's possible that this 
+             * function has modified them since, so we need to do our own restore.
+             */
+            int i = 0;
+            foreach(TokenDeclVar argVar in curDeclFunc.argDecl.varDict)
+            {
+                CompValu argLoc = argVar.location;
+                argLoc.PopPre(this, argVar.name);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, objArray);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, i);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldelem_Ref);
+                if(DEBUG_STACKCAPRES)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n    arg:" + argVar.name.val + "=");
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                    ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                }
+                TypeCast.CastTopOfStack(this, argVar.name, tokenTypeObj, argLoc.type, true);
+                argLoc.PopPost(this, argVar.name);
+                i++;
+            }
+
+            /*
+             * Restore local and temp values from object array, unboxing as needed.
+             */
+            foreach(ScriptMyLocal lcl in activeTemps)
+            {
+                Type t = lcl.type;
+                Type u = t;
+                if(t == typeof(HeapTrackerList))
+                    u = typeof(LSL_List);
+                if(t == typeof(HeapTrackerObject))
+                    u = typeof(object);
+                if(t == typeof(HeapTrackerString))
+                    u = typeof(string);
+                if(u != t)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Ldloc, lcl);
+                }
+                ilGen.Emit(curDeclFunc, OpCodes.Ldloc, objArray);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldc_I4, i++);
+                ilGen.Emit(curDeclFunc, OpCodes.Ldelem_Ref);
+                if(DEBUG_STACKCAPRES)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n    lcl:" + lcl.name + "=");
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                    ilGen.Emit(curDeclFunc, OpCodes.Dup);
+                    ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+                }
+                if(u.IsValueType)
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Unbox_Any, u);
+                }
+                else if(u != typeof(object))
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Castclass, u);
+                }
+                if(u != t)
+                {
+                    if(t == typeof(HeapTrackerList))
+                        HeapTrackerList.GenPop(curDeclFunc, ilGen);
+                    if(t == typeof(HeapTrackerObject))
+                        HeapTrackerObject.GenPop(curDeclFunc, ilGen);
+                    if(t == typeof(HeapTrackerString))
+                        HeapTrackerString.GenPop(curDeclFunc, ilGen);
+                }
+                else
+                {
+                    ilGen.Emit(curDeclFunc, OpCodes.Stloc, lcl);
+                }
+            }
+            if(DEBUG_STACKCAPRES)
+            {
+                ilGen.Emit(curDeclFunc, OpCodes.Ldstr, "\n");
+                ilGen.Emit(curDeclFunc, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            OutputCallNoSwitchStmt();
+        }
+
+        /**
+         * @brief Output a switch statement with a case for each possible 
+         *        value of whatever callNo is currently active, either 
+         *        __mainCallNo or one of the try/catch/finally's callNos.
+         *
+         *   switch (callNo) {
+         *      case 0: goto __call_0;
+         *      case 1: goto __call_1;
+         *      ...
+         *   }
+         *   throw new ScriptBadCallNoException (callNo);
+         */
+        private void OutputCallNoSwitchStmt()
+        {
+            ScriptMyLabel[] callLabels = new ScriptMyLabel[actCallLabels.Count];
+            foreach(CallLabel cl in actCallLabels)
+            {
+                callLabels[cl.index] = cl.callLabel;
+            }
+            GetCallNo(curDeclFunc, actCallNo);
+            ilGen.Emit(curDeclFunc, OpCodes.Switch, callLabels);
+
+            GetCallNo(curDeclFunc, actCallNo);
+            ilGen.Emit(curDeclFunc, OpCodes.Newobj, scriptBadCallNoExceptionConstructorInfo);
+            ilGen.Emit(curDeclFunc, OpCodes.Throw);
+        }
+
+        /**
+         * @brief There is one of these per call that can possibly call CheckRun(),
+         *        including direct calls to CheckRun().
+         *        They mark points that the stack capture/restore code will save & restore to.
+         *        All object-code level local vars active at the call label's point will 
+         *        be saved & restored.
+         *
+         *            callNo = 5;
+         *        __call_5:
+         *            push call arguments from temps
+         *            call SomethingThatCallsCheckRun()
+         *
+         *        If SomethingThatCallsCheckRun() actually calls CheckRun(), our restore code
+         *        will restore our args, locals & temps, then jump to __call_5, which will then 
+         *        call SomethingThatCallsCheckRun() again, which will restore its stuff likewise.
+         *        When eventually the actual CheckRun() call is restored, it will turn off restore 
+         *        mode (by changing callMode from CallMode_RESTORE to CallMode_NORMAL) and return, 
+         *        allowing the code to run normally from that point.
+         */
+        public class CallLabel
+        {
+            public int index;       // sequential integer, starting at 0, within actCallLabels
+                                    // - used for the switch statement
+            public ScriptMyLabel callLabel;   // the actual label token
+
+            public CallLabel(ScriptCodeGen scg, Token errorAt)
+            {
+                if(scg.openCallLabel != null)
+                    throw new Exception("call label already open");
+
+                if(!scg.curDeclFunc.IsFuncTrivial(scg))
+                {
+                    this.index = scg.actCallLabels.Count;
+                    string name = "__call_" + index + "_" + scg.allCallLabels.Count;
+
+                    /*
+                     * Make sure eval stack is empty because the frame capture/restore 
+                     * code expects such (restore switch stmt has an empty stack).
+                     */
+                    int depth = ((ScriptCollector)scg.ilGen).stackDepth.Count;
+                    if(depth > 0)
+                    {
+                        // maybe need to call Trivialize()
+                        throw new Exception("call label stack depth " + depth + " at " + errorAt.SrcLoc);
+                    }
+
+                    /*
+                     * Eval stack is empty so the restore code can handle it.
+                     */
+                    this.index = scg.actCallLabels.Count;
+                    scg.actCallLabels.AddLast(this);
+                    scg.allCallLabels.AddLast(this);
+                    this.callLabel = scg.ilGen.DefineLabel(name);
+                    scg.SetCallNo(errorAt, scg.actCallNo, this.index);
+                    scg.ilGen.MarkLabel(this.callLabel);
+                }
+
+                scg.openCallLabel = this;
+            }
+        };
+
+        /**
+         * @brief generate code for an arbitrary statement.
+         */
+        private void GenerateStmt(TokenStmt stmt)
+        {
+            errorMessageToken = stmt;
+            if(stmt is TokenDeclVar)
+            {
+                GenerateDeclVar((TokenDeclVar)stmt);
+                return;
+            }
+            if(stmt is TokenStmtBlock)
+            {
+                GenerateStmtBlock((TokenStmtBlock)stmt);
+                return;
+            }
+            if(stmt is TokenStmtBreak)
+            {
+                GenerateStmtBreak((TokenStmtBreak)stmt);
+                return;
+            }
+            if(stmt is TokenStmtCont)
+            {
+                GenerateStmtCont((TokenStmtCont)stmt);
+                return;
+            }
+            if(stmt is TokenStmtDo)
+            {
+                GenerateStmtDo((TokenStmtDo)stmt);
+                return;
+            }
+            if(stmt is TokenStmtFor)
+            {
+                GenerateStmtFor((TokenStmtFor)stmt);
+                return;
+            }
+            if(stmt is TokenStmtForEach)
+            {
+                GenerateStmtForEach((TokenStmtForEach)stmt);
+                return;
+            }
+            if(stmt is TokenStmtIf)
+            {
+                GenerateStmtIf((TokenStmtIf)stmt);
+                return;
+            }
+            if(stmt is TokenStmtJump)
+            {
+                GenerateStmtJump((TokenStmtJump)stmt);
+                return;
+            }
+            if(stmt is TokenStmtLabel)
+            {
+                GenerateStmtLabel((TokenStmtLabel)stmt);
+                return;
+            }
+            if(stmt is TokenStmtNewobj)
+            {
+                GenerateStmtNewobj((TokenStmtNewobj)stmt);
+                return;
+            }
+            if(stmt is TokenStmtNull)
+            {
+                return;
+            }
+            if(stmt is TokenStmtRet)
+            {
+                GenerateStmtRet((TokenStmtRet)stmt);
+                return;
+            }
+            if(stmt is TokenStmtRVal)
+            {
+                GenerateStmtRVal((TokenStmtRVal)stmt);
+                return;
+            }
+            if(stmt is TokenStmtState)
+            {
+                GenerateStmtState((TokenStmtState)stmt);
+                return;
+            }
+            if(stmt is TokenStmtSwitch)
+            {
+                GenerateStmtSwitch((TokenStmtSwitch)stmt);
+                return;
+            }
+            if(stmt is TokenStmtThrow)
+            {
+                GenerateStmtThrow((TokenStmtThrow)stmt);
+                return;
+            }
+            if(stmt is TokenStmtTry)
+            {
+                GenerateStmtTry((TokenStmtTry)stmt);
+                return;
+            }
+            if(stmt is TokenStmtVarIniDef)
+            {
+                GenerateStmtVarIniDef((TokenStmtVarIniDef)stmt);
+                return;
+            }
+            if(stmt is TokenStmtWhile)
+            {
+                GenerateStmtWhile((TokenStmtWhile)stmt);
+                return;
+            }
+            throw new Exception("unknown TokenStmt type " + stmt.GetType().ToString());
+        }
+
+        /**
+         * @brief generate statement block (ie, with braces)
+         */
+        private void GenerateStmtBlock(TokenStmtBlock stmtBlock)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Push new current statement block pointer for anyone who cares.
+             */
+            TokenStmtBlock oldStmtBlock = curStmtBlock;
+            curStmtBlock = stmtBlock;
+
+            /*
+             * Output the statements that make up the block.
+             */
+            for(Token t = stmtBlock.statements; t != null; t = t.nextToken)
+            {
+                GenerateStmt((TokenStmt)t);
+            }
+
+            /*
+             * Pop the current statement block.
+             */
+            curStmtBlock = oldStmtBlock;
+        }
+
+        /**
+         * @brief output code for a 'break' statement
+         */
+        private void GenerateStmtBreak(TokenStmtBreak breakStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Make sure we are in a breakable situation.
+             */
+            if(curBreakTarg == null)
+            {
+                ErrorMsg(breakStmt, "not in a breakable situation");
+                return;
+            }
+
+            /*
+             * Tell anyone who cares that the break target was actually used.
+             */
+            curBreakTarg.used = true;
+
+            /*
+             * Output the instructions.
+             */
+            EmitJumpCode(curBreakTarg.label, curBreakTarg.block, breakStmt);
+        }
+
+        /**
+         * @brief output code for a 'continue' statement
+         */
+        private void GenerateStmtCont(TokenStmtCont contStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Make sure we are in a contable situation.
+             */
+            if(curContTarg == null)
+            {
+                ErrorMsg(contStmt, "not in a continueable situation");
+                return;
+            }
+
+            /*
+             * Tell anyone who cares that the continue target was actually used.
+             */
+            curContTarg.used = true;
+
+            /*
+             * Output the instructions.
+             */
+            EmitJumpCode(curContTarg.label, curContTarg.block, contStmt);
+        }
+
+        /**
+         * @brief output code for a 'do' statement
+         */
+        private void GenerateStmtDo(TokenStmtDo doStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            BreakContTarg oldContTarg = curContTarg;
+            ScriptMyLabel loopLabel = ilGen.DefineLabel("doloop_" + doStmt.Unique);
+
+            curBreakTarg = new BreakContTarg(this, "dobreak_" + doStmt.Unique);
+            curContTarg = new BreakContTarg(this, "docont_" + doStmt.Unique);
+
+            ilGen.MarkLabel(loopLabel);
+            GenerateStmt(doStmt.bodyStmt);
+            if(curContTarg.used)
+            {
+                ilGen.MarkLabel(curContTarg.label);
+                mightGetHere = true;
+            }
+
+            if(mightGetHere)
+            {
+                EmitCallCheckRun(doStmt, false);
+                CompValu testRVal = GenerateFromRVal(doStmt.testRVal);
+                if(IsConstBoolExprTrue(testRVal))
+                {
+
+                    /*
+                     * Unconditional looping, unconditional branch and
+                     * say we never fall through to next statement.
+                     */
+                    ilGen.Emit(doStmt, OpCodes.Br, loopLabel);
+                    mightGetHere = false;
+                }
+                else
+                {
+
+                    /*
+                     * Conditional looping, test and brach back to top of loop.
+                     */
+                    testRVal.PushVal(this, doStmt.testRVal, tokenTypeBool);
+                    ilGen.Emit(doStmt, OpCodes.Brtrue, loopLabel);
+                }
+            }
+
+            /*
+             * If 'break' statement was used, output target label.
+             * And assume that since a 'break' statement was used, it's possible for the code to get here.
+             */
+            if(curBreakTarg.used)
+            {
+                ilGen.MarkLabel(curBreakTarg.label);
+                mightGetHere = true;
+            }
+
+            curBreakTarg = oldBreakTarg;
+            curContTarg = oldContTarg;
+        }
+
+        /**
+         * @brief output code for a 'for' statement
+         */
+        private void GenerateStmtFor(TokenStmtFor forStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            BreakContTarg oldContTarg = curContTarg;
+            ScriptMyLabel loopLabel = ilGen.DefineLabel("forloop_" + forStmt.Unique);
+
+            curBreakTarg = new BreakContTarg(this, "forbreak_" + forStmt.Unique);
+            curContTarg = new BreakContTarg(this, "forcont_" + forStmt.Unique);
+
+            if(forStmt.initStmt != null)
+            {
+                GenerateStmt(forStmt.initStmt);
+            }
+            ilGen.MarkLabel(loopLabel);
+
+            /*
+             * See if we have a test expression that is other than a constant TRUE.
+             * If so, test it and conditionally branch to end if false.
+             */
+            if(forStmt.testRVal != null)
+            {
+                CompValu testRVal = GenerateFromRVal(forStmt.testRVal);
+                if(!IsConstBoolExprTrue(testRVal))
+                {
+                    testRVal.PushVal(this, forStmt.testRVal, tokenTypeBool);
+                    ilGen.Emit(forStmt, OpCodes.Brfalse, curBreakTarg.label);
+                    curBreakTarg.used = true;
+                }
+            }
+
+            /*
+             * Output loop body.
+             */
+            GenerateStmt(forStmt.bodyStmt);
+
+            /*
+             * Here's where a 'continue' statement jumps to.
+             */
+            if(curContTarg.used)
+            {
+                ilGen.MarkLabel(curContTarg.label);
+                mightGetHere = true;
+            }
+
+            if(mightGetHere)
+            {
+
+                /*
+                 * After checking for excessive CPU time, output increment statement, if any.
+                 */
+                EmitCallCheckRun(forStmt, false);
+                if(forStmt.incrRVal != null)
+                {
+                    GenerateFromRVal(forStmt.incrRVal);
+                }
+
+                /*
+                 * Unconditional branch back to beginning of loop.
+                 */
+                ilGen.Emit(forStmt, OpCodes.Br, loopLabel);
+            }
+
+            /*
+             * If test needs label, output label for it to jump to.
+             * Otherwise, clear mightGetHere as we know loop never
+             * falls out the bottom.
+             */
+            mightGetHere = curBreakTarg.used;
+            if(mightGetHere)
+            {
+                ilGen.MarkLabel(curBreakTarg.label);
+            }
+
+            curBreakTarg = oldBreakTarg;
+            curContTarg = oldContTarg;
+        }
+
+        private void GenerateStmtForEach(TokenStmtForEach forEachStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            BreakContTarg oldContTarg = curContTarg;
+            CompValu keyLVal = null;
+            CompValu valLVal = null;
+            CompValu arrayRVal = GenerateFromRVal(forEachStmt.arrayRVal);
+
+            if(forEachStmt.keyLVal != null)
+            {
+                keyLVal = GenerateFromLVal(forEachStmt.keyLVal);
+                if(!(keyLVal.type is TokenTypeObject))
+                {
+                    ErrorMsg(forEachStmt.arrayRVal, "must be object");
+                }
+            }
+            if(forEachStmt.valLVal != null)
+            {
+                valLVal = GenerateFromLVal(forEachStmt.valLVal);
+                if(!(valLVal.type is TokenTypeObject))
+                {
+                    ErrorMsg(forEachStmt.arrayRVal, "must be object");
+                }
+            }
+            if(!(arrayRVal.type is TokenTypeArray))
+            {
+                ErrorMsg(forEachStmt.arrayRVal, "must be an array");
+            }
+
+            curBreakTarg = new BreakContTarg(this, "foreachbreak_" + forEachStmt.Unique);
+            curContTarg = new BreakContTarg(this, "foreachcont_" + forEachStmt.Unique);
+
+            CompValuTemp indexVar = new CompValuTemp(new TokenTypeInt(forEachStmt), this);
+            ScriptMyLabel loopLabel = ilGen.DefineLabel("foreachloop_" + forEachStmt.Unique);
+
+            // indexVar = 0
+            ilGen.Emit(forEachStmt, OpCodes.Ldc_I4_0);
+            indexVar.Pop(this, forEachStmt);
+
+            ilGen.MarkLabel(loopLabel);
+
+            // key = array.__pub_index (indexVar);
+            // if (key == null) goto curBreakTarg;
+            if(keyLVal != null)
+            {
+                keyLVal.PopPre(this, forEachStmt.keyLVal);
+                arrayRVal.PushVal(this, forEachStmt.arrayRVal);
+                indexVar.PushVal(this, forEachStmt);
+                ilGen.Emit(forEachStmt, OpCodes.Call, xmrArrPubIndexMethod);
+                keyLVal.PopPost(this, forEachStmt.keyLVal);
+                keyLVal.PushVal(this, forEachStmt.keyLVal);
+                ilGen.Emit(forEachStmt, OpCodes.Brfalse, curBreakTarg.label);
+                curBreakTarg.used = true;
+            }
+
+            // val = array._pub_value (indexVar);
+            // if (val == null) goto curBreakTarg;
+            if(valLVal != null)
+            {
+                valLVal.PopPre(this, forEachStmt.valLVal);
+                arrayRVal.PushVal(this, forEachStmt.arrayRVal);
+                indexVar.PushVal(this, forEachStmt);
+                ilGen.Emit(forEachStmt, OpCodes.Call, xmrArrPubValueMethod);
+                valLVal.PopPost(this, forEachStmt.valLVal);
+                if(keyLVal == null)
+                {
+                    valLVal.PushVal(this, forEachStmt.valLVal);
+                    ilGen.Emit(forEachStmt, OpCodes.Brfalse, curBreakTarg.label);
+                    curBreakTarg.used = true;
+                }
+            }
+
+            // indexVar ++;
+            indexVar.PushVal(this, forEachStmt);
+            ilGen.Emit(forEachStmt, OpCodes.Ldc_I4_1);
+            ilGen.Emit(forEachStmt, OpCodes.Add);
+            indexVar.Pop(this, forEachStmt);
+
+            // body statement
+            GenerateStmt(forEachStmt.bodyStmt);
+
+            // continue label
+            if(curContTarg.used)
+            {
+                ilGen.MarkLabel(curContTarg.label);
+                mightGetHere = true;
+            }
+
+            // call CheckRun()
+            if(mightGetHere)
+            {
+                EmitCallCheckRun(forEachStmt, false);
+                ilGen.Emit(forEachStmt, OpCodes.Br, loopLabel);
+            }
+
+            // break label
+            ilGen.MarkLabel(curBreakTarg.label);
+            mightGetHere = true;
+
+            curBreakTarg = oldBreakTarg;
+            curContTarg = oldContTarg;
+        }
+
+        /**
+         * @brief output code for an 'if' statement
+         * Braces are necessary because what may be one statement for trueStmt or elseStmt in
+         * the script may translate to more than one statement in the resultant C# code.
+         */
+        private void GenerateStmtIf(TokenStmtIf ifStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            bool constVal;
+
+            /*
+             * Test condition and see if constant test expression.
+             */
+            CompValu testRVal = GenerateFromRVal(ifStmt.testRVal);
+            if(IsConstBoolExpr(testRVal, out constVal))
+            {
+
+                /*
+                 * Constant, output just either the true or else part.
+                 */
+                if(constVal)
+                {
+                    GenerateStmt(ifStmt.trueStmt);
+                }
+                else if(ifStmt.elseStmt != null)
+                {
+                    GenerateStmt(ifStmt.elseStmt);
+                }
+            }
+            else if(ifStmt.elseStmt == null)
+            {
+
+                /*
+                 * This is an 'if' statement without an 'else' clause.
+                 */
+                testRVal.PushVal(this, ifStmt.testRVal, tokenTypeBool);
+                ScriptMyLabel doneLabel = ilGen.DefineLabel("ifdone_" + ifStmt.Unique);
+                ilGen.Emit(ifStmt, OpCodes.Brfalse, doneLabel);  // brfalse doneLabel
+                GenerateStmt(ifStmt.trueStmt);                   // generate true body code
+                ilGen.MarkLabel(doneLabel);
+                mightGetHere = true;                              // there's always a possibility of getting here
+            }
+            else
+            {
+
+                /*
+                 * This is an 'if' statement with an 'else' clause.
+                 */
+                testRVal.PushVal(this, ifStmt.testRVal, tokenTypeBool);
+                ScriptMyLabel elseLabel = ilGen.DefineLabel("ifelse_" + ifStmt.Unique);
+                ilGen.Emit(ifStmt, OpCodes.Brfalse, elseLabel);  // brfalse elseLabel
+                GenerateStmt(ifStmt.trueStmt);                   // generate true body code
+                bool trueMightGetHere = mightGetHere;             // save whether or not true falls through
+                ScriptMyLabel doneLabel = ilGen.DefineLabel("ifdone_" + ifStmt.Unique);
+                ilGen.Emit(ifStmt, OpCodes.Br, doneLabel);       // branch to done
+                ilGen.MarkLabel(elseLabel);                      // beginning of else code
+                mightGetHere = true;                              // the top of the else might be executed
+                GenerateStmt(ifStmt.elseStmt);                   // output else code
+                ilGen.MarkLabel(doneLabel);                      // where end of true clause code branches to
+                mightGetHere |= trueMightGetHere;                 // gets this far if either true or else falls through
+            }
+        }
+
+        /**
+         * @brief output code for a 'jump' statement
+         */
+        private void GenerateStmtJump(TokenStmtJump jumpStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Make sure the target label is defined somewhere in the function.
+             */
+            TokenStmtLabel stmtLabel;
+            if(!curDeclFunc.labels.TryGetValue(jumpStmt.label.val, out stmtLabel))
+            {
+                ErrorMsg(jumpStmt, "undefined label " + jumpStmt.label.val);
+                return;
+            }
+            if(!stmtLabel.labelTagged)
+            {
+                stmtLabel.labelStruct = ilGen.DefineLabel("jump_" + stmtLabel.name.val);
+                stmtLabel.labelTagged = true;
+            }
+
+            /*
+             * Emit instructions to do the jump.
+             */
+            EmitJumpCode(stmtLabel.labelStruct, stmtLabel.block, jumpStmt);
+        }
+
+        /**
+         * @brief Emit code to jump to a label
+         * @param target = label being jumped to
+         * @param targetsBlock = { ... } the label is defined in
+         */
+        private void EmitJumpCode(ScriptMyLabel target, TokenStmtBlock targetsBlock, Token errorAt)
+        {
+            /*
+             * Jumps never fall through.
+             */
+            mightGetHere = false;
+
+            /*
+             * Find which block the target label is in.  Must be in this or an outer block,
+             * no laterals allowed.  And if we exit a try/catch block, use Leave instead of Br.
+             *
+             *    jump lateral;
+             *    {
+             *        @lateral;
+             *    }
+             */
+            bool useLeave = false;
+            TokenStmtBlock stmtBlock;
+            Stack<TokenStmtTry> finallyBlocksCalled = new Stack<TokenStmtTry>();
+            for(stmtBlock = curStmtBlock; stmtBlock != targetsBlock; stmtBlock = stmtBlock.outerStmtBlock)
+            {
+                if(stmtBlock == null)
+                {
+                    ErrorMsg(errorAt, "no lateral jumps allowed");
+                    return;
+                }
+                if(stmtBlock.isFinally)
+                {
+                    ErrorMsg(errorAt, "cannot jump out of finally");
+                    return;
+                }
+                if(stmtBlock.isTry || stmtBlock.isCatch)
+                    useLeave = true;
+                if((stmtBlock.tryStmt != null) && (stmtBlock.tryStmt.finallyStmt != null))
+                {
+                    finallyBlocksCalled.Push(stmtBlock.tryStmt);
+                }
+            }
+
+            /*
+             * If popping through more than one finally block, we have to break it down for the stack 
+             * capture and restore code, one finally block at a time.
+             *
+             *     try {
+             *         try {
+             *             try {
+             *                 jump exit;
+             *             } finally {
+             *                 llOwnerSay ("exiting inner");
+             *             }
+             *         } finally {
+             *             llOwnerSay ("exiting middle");
+             *         }
+             *     } finally {
+             *         llOwnerSay ("exiting outer");
+             *     }
+             *   @exit;
+             *
+             *     try {
+             *         try {
+             *             try {
+             *                 jump intr2_exit;         <<< gets its own tryNo call label so inner try knows where to restore to
+             *             } finally {
+             *                 llOwnerSay ("exiting inner");
+             *             }
+             *             jump outtry2;
+             *           @intr2_exit; jump intr1_exit;  <<< gets its own tryNo call label so middle try knows where to restore to
+             *           @outtry2;
+             *         } finally {
+             *             llOwnerSay ("exiting middle");
+             *         }
+             *         jump outtry1;
+             *       @intr1_exit: jump exit;            <<< gets its own tryNo call label so outer try knows where to restore to
+             *       @outtry1;
+             *     } finally {
+             *         llOwnerSay ("exiting outer");
+             *     }
+             *   @exit;
+             */
+            int level = 0;
+            while(finallyBlocksCalled.Count > 1)
+            {
+                TokenStmtTry finallyBlock = finallyBlocksCalled.Pop();
+                string intername = "intr" + (++level) + "_" + target.name;
+                IntermediateLeave iLeave;
+                if(!finallyBlock.iLeaves.TryGetValue(intername, out iLeave))
+                {
+                    iLeave = new IntermediateLeave();
+                    iLeave.jumpIntoLabel = ilGen.DefineLabel(intername);
+                    iLeave.jumpAwayLabel = target;
+                    finallyBlock.iLeaves.Add(intername, iLeave);
+                }
+                target = iLeave.jumpIntoLabel;
+            }
+
+            /*
+             * Finally output the branch/leave opcode.
+             * If using Leave, prefix with a call label in case the corresponding finally block
+             * calls CheckRun() and that CheckRun() captures the stack, it will have a point to 
+             * restore to that will properly jump back into the finally block.
+             */
+            if(useLeave)
+            {
+                new CallLabel(this, errorAt);
+                ilGen.Emit(errorAt, OpCodes.Leave, target);
+                openCallLabel = null;
+            }
+            else
+            {
+                ilGen.Emit(errorAt, OpCodes.Br, target);
+            }
+        }
+
+        /**
+         * @brief output code for a jump target label statement.
+         * If there are any backward jumps to the label, do a CheckRun() also.
+         */
+        private void GenerateStmtLabel(TokenStmtLabel labelStmt)
+        {
+            if(!labelStmt.labelTagged)
+            {
+                labelStmt.labelStruct = ilGen.DefineLabel("jump_" + labelStmt.name.val);
+                labelStmt.labelTagged = true;
+            }
+            ilGen.MarkLabel(labelStmt.labelStruct);
+            if(labelStmt.hasBkwdRefs)
+            {
+                EmitCallCheckRun(labelStmt, false);
+            }
+
+            /*
+             * We are going to say that the label falls through.
+             * It would be nice if we could analyze all referencing
+             * goto's to see if all of them are not used but we are
+             * going to assume that if the script writer put a label
+             * somewhere, it is probably going to be used.
+             */
+            mightGetHere = true;
+        }
+
+        /**
+         * @brief Generate code for a script-defined type's <typename>.$new(<argsig>) method.
+         *        It is used to malloc the object and initialize it.
+         *        It is defined as a script-defined type static method, so the object level
+         *        method gets the XMRInstance pointer passed as arg 0, and the method is 
+         *        supposed to return the allocated and constructed XMRSDTypeClObj
+         *        object pointer.
+         */
+        private void GenerateStmtNewobj(TokenStmtNewobj newobjStmt)
+        {
+            /*
+             * First off, malloc a new empty XMRSDTypeClObj object
+             * then call the XMRSDTypeClObj()-level constructor.
+             * Store the result in local var $objptr.
+             */
+            newobjStmt.objptrVar.location.PopPre(this, newobjStmt);
+            ilGen.Emit(newobjStmt, OpCodes.Ldarg_0);
+            ilGen.Emit(newobjStmt, OpCodes.Ldc_I4, curDeclFunc.sdtClass.sdTypeIndex);
+            ilGen.Emit(newobjStmt, OpCodes.Newobj, sdtClassConstructorInfo);
+            newobjStmt.objptrVar.location.PopPost(this, newobjStmt);
+
+            /*
+             * Now call the script-level constructor.
+             * Pass the object pointer in $objptr as it's 'this' argument.
+             * The rest of the args are the script-visible args and are just copied from $new() call.
+             */
+            GenerateFromRValCall(newobjStmt.rValCall);
+
+            /*
+             * Put object pointer in retval so it gets returned to caller.
+             */
+            newobjStmt.objptrVar.location.PushVal(this, newobjStmt);
+            ilGen.Emit(newobjStmt, OpCodes.Stloc, retValue);
+
+            /*
+             * Exit the function like a return statement.
+             * And thus we don't fall through.
+             */
+            ilGen.Emit(newobjStmt, OpCodes.Leave, retLabel);
+            mightGetHere = false;
+        }
+
+        /**
+         * @brief output code for a return statement.
+         * @param retStmt = return statement token, including return value if any
+         */
+        private void GenerateStmtRet(TokenStmtRet retStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            for(TokenStmtBlock stmtBlock = curStmtBlock; stmtBlock != null; stmtBlock = stmtBlock.outerStmtBlock)
+            {
+                if(stmtBlock.isFinally)
+                {
+                    ErrorMsg(retStmt, "cannot return out of finally");
+                    return;
+                }
+            }
+
+            if(curDeclFunc.retType is TokenTypeVoid)
+            {
+                if(retStmt.rVal != null)
+                {
+                    ErrorMsg(retStmt, "function returns void, no value allowed");
+                    return;
+                }
+            }
+            else
+            {
+                if(retStmt.rVal == null)
+                {
+                    ErrorMsg(retStmt, "function requires return value type " + curDeclFunc.retType.ToString());
+                    return;
+                }
+                CompValu rVal = GenerateFromRVal(retStmt.rVal);
+                rVal.PushVal(this, retStmt.rVal, curDeclFunc.retType);
+                ilGen.Emit(retStmt, OpCodes.Stloc, retValue);
+            }
+
+            /*
+             * Use a OpCodes.Leave instruction to break out of any try { } blocks.
+             * All Leave's inside script-defined try { } need call labels (see GenerateStmtTry()).
+             */
+            bool brokeOutOfTry = false;
+            for(TokenStmtBlock stmtBlock = curStmtBlock; stmtBlock != null; stmtBlock = stmtBlock.outerStmtBlock)
+            {
+                if(stmtBlock.isTry)
+                {
+                    brokeOutOfTry = true;
+                    break;
+                }
+            }
+            if(brokeOutOfTry)
+                new CallLabel(this, retStmt);
+            ilGen.Emit(retStmt, OpCodes.Leave, retLabel);
+            if(brokeOutOfTry)
+                openCallLabel = null;
+
+            /*
+             * 'return' statements never fall through.
+             */
+            mightGetHere = false;
+        }
+
+        /**
+         * @brief the statement is just an expression, most likely an assignment or a ++ or -- thing.
+         */
+        private void GenerateStmtRVal(TokenStmtRVal rValStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            GenerateFromRVal(rValStmt.rVal);
+        }
+
+        /**
+         * @brief generate code for a 'state' statement that transitions state.
+         * It sets the new state by throwing a ScriptChangeStateException.
+         */
+        private void GenerateStmtState(TokenStmtState stateStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            int index = 0;  // 'default' state
+
+            /*
+             * Set new state value by throwing an exception.
+             * These exceptions aren't catchable by script-level try { } catch { }.
+             */
+            if((stateStmt.state != null) && !stateIndices.TryGetValue(stateStmt.state.val, out index))
+            {
+                // The moron XEngine compiles scripts that reference undefined states.
+                // So rather than produce a compile-time error, we'll throw an exception at runtime.
+                // ErrorMsg (stateStmt, "undefined state " + stateStmt.state.val);
+
+                // throw new UndefinedStateException (stateStmt.state.val);
+                ilGen.Emit(stateStmt, OpCodes.Ldstr, stateStmt.state.val);
+                ilGen.Emit(stateStmt, OpCodes.Newobj, scriptUndefinedStateExceptionConstructorInfo);
+            }
+            else
+            {
+                ilGen.Emit(stateStmt, OpCodes.Ldc_I4, index);  // new state's index
+                ilGen.Emit(stateStmt, OpCodes.Newobj, scriptChangeStateExceptionConstructorInfo);
+            }
+            ilGen.Emit(stateStmt, OpCodes.Throw);
+
+            /*
+             * 'state' statements never fall through.
+             */
+            mightGetHere = false;
+        }
+
+        /**
+         * @brief output code for a 'switch' statement
+         */
+        private void GenerateStmtSwitch(TokenStmtSwitch switchStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Output code to calculate index.
+             */
+            CompValu testRVal = GenerateFromRVal(switchStmt.testRVal);
+
+            /*
+             * Generate code based on string or integer index.
+             */
+            if((testRVal.type is TokenTypeKey) || (testRVal.type is TokenTypeStr))
+            {
+                GenerateStmtSwitchStr(testRVal, switchStmt);
+            }
+            else
+            {
+                GenerateStmtSwitchInt(testRVal, switchStmt);
+            }
+        }
+
+        private void GenerateStmtSwitchInt(CompValu testRVal, TokenStmtSwitch switchStmt)
+        {
+            testRVal.PushVal(this, switchStmt.testRVal, tokenTypeInt);
+
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            ScriptMyLabel defaultLabel = null;
+            TokenSwitchCase sortedCases = null;
+            TokenSwitchCase defaultCase = null;
+
+            curBreakTarg = new BreakContTarg(this, "switchbreak_" + switchStmt.Unique);
+
+            /*
+             * Build list of cases sorted by ascending values.
+             * There should not be any overlapping of values.
+             */
+            for(TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase)
+            {
+                thisCase.label = ilGen.DefineLabel("case_" + thisCase.Unique);
+
+                /*
+                 * The default case if any, goes in its own separate slot.
+                 */
+                if(thisCase.rVal1 == null)
+                {
+                    if(defaultCase != null)
+                    {
+                        ErrorMsg(thisCase, "only one default case allowed");
+                        ErrorMsg(defaultCase, "...prior default case");
+                        return;
+                    }
+                    defaultCase = thisCase;
+                    defaultLabel = thisCase.label;
+                    continue;
+                }
+
+                /*
+                 * Evaluate case operands, they must be compile-time integer constants.
+                 */
+                CompValu rVal = GenerateFromRVal(thisCase.rVal1);
+                if(!IsConstIntExpr(rVal, out thisCase.val1))
+                {
+                    ErrorMsg(thisCase.rVal1, "must be compile-time char or integer constant");
+                    return;
+                }
+                thisCase.val2 = thisCase.val1;
+                if(thisCase.rVal2 != null)
+                {
+                    rVal = GenerateFromRVal(thisCase.rVal2);
+                    if(!IsConstIntExpr(rVal, out thisCase.val2))
+                    {
+                        ErrorMsg(thisCase.rVal2, "must be compile-time char or integer constant");
+                        return;
+                    }
+                }
+                if(thisCase.val2 < thisCase.val1)
+                {
+                    ErrorMsg(thisCase.rVal2, "must be .ge. first value for the case");
+                    return;
+                }
+
+                /*
+                 * Insert into list, sorted by value.
+                 * Note that both limits are inclusive.
+                 */
+                TokenSwitchCase lastCase = null;
+                TokenSwitchCase nextCase;
+                for(nextCase = sortedCases; nextCase != null; nextCase = nextCase.nextSortedCase)
+                {
+                    if(nextCase.val1 > thisCase.val2)
+                        break;
+                    if(nextCase.val2 >= thisCase.val1)
+                    {
+                        ErrorMsg(thisCase, "value used by previous case");
+                        ErrorMsg(nextCase, "...previous case");
+                        return;
+                    }
+                    lastCase = nextCase;
+                }
+                thisCase.nextSortedCase = nextCase;
+                if(lastCase == null)
+                {
+                    sortedCases = thisCase;
+                }
+                else
+                {
+                    lastCase.nextSortedCase = thisCase;
+                }
+            }
+
+            if(defaultLabel == null)
+            {
+                defaultLabel = ilGen.DefineLabel("default_" + switchStmt.Unique);
+            }
+
+            /*
+             * Output code to jump to the case statement's labels based on integer index on stack.
+             * Note that each case still has the integer index on stack when jumped to.
+             */
+            int offset = 0;
+            for(TokenSwitchCase thisCase = sortedCases; thisCase != null;)
+            {
+
+                /*
+                 * Scan through list of cases to find the maximum number of cases who's numvalues-to-case ratio
+                 * is from 0.5 to 2.0.  If such a group is found, use a CIL switch for them.  If not, just use a
+                 * compare-and-branch for the current case.
+                 */
+                int numCases = 0;
+                int numFound = 0;
+                int lowValue = thisCase.val1;
+                int numValues = 0;
+                for(TokenSwitchCase scanCase = thisCase; scanCase != null; scanCase = scanCase.nextSortedCase)
+                {
+                    int nVals = scanCase.val2 - thisCase.val1 + 1;
+                    double ratio = (double)nVals / (double)(++numCases);
+                    if((ratio >= 0.5) && (ratio <= 2.0))
+                    {
+                        numFound = numCases;
+                        numValues = nVals;
+                    }
+                }
+                if(numFound > 1)
+                {
+
+                    /*
+                     * There is a group of case's, starting with thisCase, that fall within our criteria, ie, 
+                     * that have a nice density of meaningful jumps.
+                     *
+                     * So first generate an array of jumps to the default label (explicit or implicit).
+                     */
+                    ScriptMyLabel[] labels = new ScriptMyLabel[numValues];
+                    for(int i = 0; i < numValues; i++)
+                    {
+                        labels[i] = defaultLabel;
+                    }
+
+                    /*
+                     * Next, for each case in that group, fill in the corresponding array entries to jump to
+                     * that case's label.
+                     */
+                    do
+                    {
+                        for(int i = thisCase.val1; i <= thisCase.val2; i++)
+                        {
+                            labels[i - lowValue] = thisCase.label;
+                        }
+                        thisCase = thisCase.nextSortedCase;
+                    } while(--numFound > 0);
+
+                    /*
+                     * Subtract the low value and do the computed jump.
+                     * The OpCodes.Switch falls through if out of range (unsigned compare).
+                     */
+                    if(offset != lowValue)
+                    {
+                        ilGen.Emit(switchStmt, OpCodes.Ldc_I4, lowValue - offset);
+                        ilGen.Emit(switchStmt, OpCodes.Sub);
+                        offset = lowValue;
+                    }
+                    ilGen.Emit(switchStmt, OpCodes.Dup);
+                    ilGen.Emit(switchStmt, OpCodes.Switch, labels);
+                }
+                else
+                {
+
+                    /*
+                     * It's not economical to do with a computed jump, so output a subtract/compare/branch
+                     * for thisCase.
+                     */
+                    if(lowValue == thisCase.val2)
+                    {
+                        ilGen.Emit(switchStmt, OpCodes.Dup);
+                        ilGen.Emit(switchStmt, OpCodes.Ldc_I4, lowValue - offset);
+                        ilGen.Emit(switchStmt, OpCodes.Beq, thisCase.label);
+                    }
+                    else
+                    {
+                        if(offset != lowValue)
+                        {
+                            ilGen.Emit(switchStmt, OpCodes.Ldc_I4, lowValue - offset);
+                            ilGen.Emit(switchStmt, OpCodes.Sub);
+                            offset = lowValue;
+                        }
+                        ilGen.Emit(switchStmt, OpCodes.Dup);
+                        ilGen.Emit(switchStmt, OpCodes.Ldc_I4, thisCase.val2 - offset);
+                        ilGen.Emit(switchStmt, OpCodes.Ble_Un, thisCase.label);
+                    }
+                    thisCase = thisCase.nextSortedCase;
+                }
+            }
+            ilGen.Emit(switchStmt, OpCodes.Br, defaultLabel);
+
+            /*
+             * Output code for the cases themselves, in the order given by the programmer, 
+             * so they fall through as programmer wants.  This includes the default case, if any.
+             *
+             * Each label is jumped to with the index still on the stack.  So pop it off in case
+             * the case body does a goto outside the switch or a return.  If the case body might
+             * fall through to the next case or the bottom of the switch, push a zero so the stack
+             * matches in all cases.
+             */
+            for(TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase)
+            {
+                ilGen.MarkLabel(thisCase.label);   // the branch comes here
+                ilGen.Emit(thisCase, OpCodes.Pop); // pop the integer index off stack
+                mightGetHere = true;            // it's possible to get here
+                for(TokenStmt stmt = thisCase.stmts; stmt != null; stmt = (TokenStmt)(stmt.nextToken))
+                {
+                    GenerateStmt(stmt);        // output the case/explicit default body
+                }
+                if(mightGetHere)
+                {
+                    ilGen.Emit(thisCase, OpCodes.Ldc_I4_0);
+                    // in case we fall through, push a dummy integer index
+                }
+            }
+
+            /*
+             * If no explicit default case, output the default label here.
+             */
+            if(defaultCase == null)
+            {
+                ilGen.MarkLabel(defaultLabel);
+                mightGetHere = true;
+            }
+
+            /*
+             * If the last case of the switch falls through out the bottom,
+             * we have to pop the index still on the stack.
+             */
+            if(mightGetHere)
+            {
+                ilGen.Emit(switchStmt, OpCodes.Pop);
+            }
+
+            /*
+             * Output the 'break' statement target label.
+             * Note that the integer index is not on the stack at this point.
+             */
+            if(curBreakTarg.used)
+            {
+                ilGen.MarkLabel(curBreakTarg.label);
+                mightGetHere = true;
+            }
+
+            curBreakTarg = oldBreakTarg;
+        }
+
+        private void GenerateStmtSwitchStr(CompValu testRVal, TokenStmtSwitch switchStmt)
+        {
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            ScriptMyLabel defaultLabel = null;
+            TokenSwitchCase caseTreeTop = null;
+            TokenSwitchCase defaultCase = null;
+
+            curBreakTarg = new BreakContTarg(this, "switchbreak_" + switchStmt.Unique);
+
+            /*
+             * Make sure value is in a temp so we don't compute it more than once.
+             */
+            if(!(testRVal is CompValuTemp))
+            {
+                CompValuTemp temp = new CompValuTemp(testRVal.type, this);
+                testRVal.PushVal(this, switchStmt);
+                temp.Pop(this, switchStmt);
+                testRVal = temp;
+            }
+
+            /*
+             * Build tree of cases.
+             * There should not be any overlapping of values.
+             */
+            for(TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase)
+            {
+                thisCase.label = ilGen.DefineLabel("case");
+
+                /*
+                 * The default case if any, goes in its own separate slot.
+                 */
+                if(thisCase.rVal1 == null)
+                {
+                    if(defaultCase != null)
+                    {
+                        ErrorMsg(thisCase, "only one default case allowed");
+                        ErrorMsg(defaultCase, "...prior default case");
+                        return;
+                    }
+                    defaultCase = thisCase;
+                    defaultLabel = thisCase.label;
+                    continue;
+                }
+
+                /*
+                 * Evaluate case operands, they must be compile-time string constants.
+                 */
+                CompValu rVal = GenerateFromRVal(thisCase.rVal1);
+                if(!IsConstStrExpr(rVal, out thisCase.str1))
+                {
+                    ErrorMsg(thisCase.rVal1, "must be compile-time string constant");
+                    continue;
+                }
+                thisCase.str2 = thisCase.str1;
+                if(thisCase.rVal2 != null)
+                {
+                    rVal = GenerateFromRVal(thisCase.rVal2);
+                    if(!IsConstStrExpr(rVal, out thisCase.str2))
+                    {
+                        ErrorMsg(thisCase.rVal2, "must be compile-time string constant");
+                        continue;
+                    }
+                }
+                if(String.Compare(thisCase.str2, thisCase.str1, StringComparison.Ordinal) < 0)
+                {
+                    ErrorMsg(thisCase.rVal2, "must be .ge. first value for the case");
+                    continue;
+                }
+
+                /*
+                 * Insert into list, sorted by value.
+                 * Note that both limits are inclusive.
+                 */
+                caseTreeTop = InsertCaseInTree(caseTreeTop, thisCase);
+            }
+
+            /*
+             * Balance tree so we end up generating code that does O(log2 n) comparisons.
+             */
+            caseTreeTop = BalanceTree(caseTreeTop);
+
+            /*
+             * Output compare and branch instructions in a tree-like fashion so we do O(log2 n) comparisons.
+             */
+            if(defaultLabel == null)
+            {
+                defaultLabel = ilGen.DefineLabel("default");
+            }
+            OutputStrCase(testRVal, caseTreeTop, defaultLabel);
+
+            /*
+             * Output code for the cases themselves, in the order given by the programmer, 
+             * so they fall through as programmer wants.  This includes the default case, if any.
+             */
+            for(TokenSwitchCase thisCase = switchStmt.cases; thisCase != null; thisCase = thisCase.nextCase)
+            {
+                ilGen.MarkLabel(thisCase.label);   // the branch comes here
+                mightGetHere = true;            // it's possible to get here
+                for(TokenStmt stmt = thisCase.stmts; stmt != null; stmt = (TokenStmt)(stmt.nextToken))
+                {
+                    GenerateStmt(stmt);        // output the case/explicit default body
+                }
+            }
+
+            /*
+             * If no explicit default case, output the default label here.
+             */
+            if(defaultCase == null)
+            {
+                ilGen.MarkLabel(defaultLabel);
+                mightGetHere = true;
+            }
+
+            /*
+             * Output the 'break' statement target label.
+             */
+            if(curBreakTarg.used)
+            {
+                ilGen.MarkLabel(curBreakTarg.label);
+                mightGetHere = true;
+            }
+
+            curBreakTarg = oldBreakTarg;
+        }
+
+        /**
+         * @brief Insert a case in a tree of cases
+         * @param r = root of existing cases to insert into
+         * @param n = new case being inserted
+         * @returns new root with new case inserted
+         */
+        private TokenSwitchCase InsertCaseInTree(TokenSwitchCase r, TokenSwitchCase n)
+        {
+            if(r == null)
+                return n;
+
+            TokenSwitchCase t = r;
+            while(true)
+            {
+                if(String.Compare(n.str2, t.str1, StringComparison.Ordinal) < 0)
+                {
+                    if(t.lowerCase == null)
+                    {
+                        t.lowerCase = n;
+                        break;
+                    }
+                    t = t.lowerCase;
+                    continue;
+                }
+                if(String.Compare(n.str1, t.str2, StringComparison.Ordinal) > 0)
+                {
+                    if(t.higherCase == null)
+                    {
+                        t.higherCase = n;
+                        break;
+                    }
+                    t = t.higherCase;
+                    continue;
+                }
+                ErrorMsg(n, "duplicate case");
+                ErrorMsg(r, "...duplicate of");
+                break;
+            }
+            return r;
+        }
+
+        /**
+         * @brief Balance a tree so left & right halves contain same number within +-1
+         * @param r = root of tree to balance
+         * @returns new root
+         */
+        private static TokenSwitchCase BalanceTree(TokenSwitchCase r)
+        {
+            if(r == null)
+                return r;
+
+            int lc = CountTree(r.lowerCase);
+            int hc = CountTree(r.higherCase);
+            TokenSwitchCase n, x;
+
+            /*
+             * If lower side is heavy, move highest nodes from lower side to 
+             * higher side until balanced.
+             */
+            while(lc > hc + 1)
+            {
+                x = ExtractHighest(r.lowerCase, out n);
+                n.lowerCase = x;
+                n.higherCase = r;
+                r.lowerCase = null;
+                r = n;
+                lc--;
+                hc++;
+            }
+
+            /*
+             * If higher side is heavy, move lowest nodes from higher side to 
+             * lower side until balanced.
+             */
+            while(hc > lc + 1)
+            {
+                x = ExtractLowest(r.higherCase, out n);
+                n.higherCase = x;
+                n.lowerCase = r;
+                r.higherCase = null;
+                r = n;
+                lc++;
+                hc--;
+            }
+
+            /*
+             * Now balance each side because they can be lopsided individually.
+             */
+            r.lowerCase = BalanceTree(r.lowerCase);
+            r.higherCase = BalanceTree(r.higherCase);
+            return r;
+        }
+
+        /**
+         * @brief Get number of nodes in a tree
+         * @param n = root of tree to count
+         * @returns number of nodes including root
+         */
+        private static int CountTree(TokenSwitchCase n)
+        {
+            if(n == null)
+                return 0;
+            return 1 + CountTree(n.lowerCase) + CountTree(n.higherCase);
+        }
+
+        // Extract highest node from a tree
+        // @param r = root of tree to extract highest from
+        // @returns new root after node has been extracted
+        //          n = node that was extracted from tree
+        private static TokenSwitchCase ExtractHighest(TokenSwitchCase r, out TokenSwitchCase n)
+        {
+            if(r.higherCase == null)
+            {
+                n = r;
+                return r.lowerCase;
+            }
+            r.higherCase = ExtractHighest(r.higherCase, out n);
+            return r;
+        }
+
+        // Extract lowest node from a tree
+        // @param r = root of tree to extract lowest from
+        // @returns new root after node has been extracted
+        //          n = node that was extracted from tree
+        private static TokenSwitchCase ExtractLowest(TokenSwitchCase r, out TokenSwitchCase n)
+        {
+            if(r.lowerCase == null)
+            {
+                n = r;
+                return r.higherCase;
+            }
+            r.lowerCase = ExtractLowest(r.lowerCase, out n);
+            return r;
+        }
+
+        /**
+         * Output code for string-style case of a switch/case to jump to the script code associated with the case.
+         * @param testRVal = value being switched on
+         * @param thisCase = case that the code is being output for
+         * @param defaultLabel = where the default clause is (or past all cases if none)
+         * Note:
+         *   Outputs code for this case and the lowerCase and higherCases if any.
+         *   If no lowerCase or higherCase, outputs a br to defaultLabel so this code never falls through.
+         */
+        private void OutputStrCase(CompValu testRVal, TokenSwitchCase thisCase, ScriptMyLabel defaultLabel)
+        {
+            /*
+             * If nothing lower on tree and there is a single case value, 
+             * just do one compare for equality.
+             */
+            if((thisCase.lowerCase == null) && (thisCase.higherCase == null) && (thisCase.str1 == thisCase.str2))
+            {
+                testRVal.PushVal(this, thisCase, tokenTypeStr);
+                ilGen.Emit(thisCase, OpCodes.Ldstr, thisCase.str1);
+                ilGen.Emit(thisCase, OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
+                ilGen.Emit(thisCase, OpCodes.Call, stringCompareMethodInfo);
+                ilGen.Emit(thisCase, OpCodes.Brfalse, thisCase.label);
+                ilGen.Emit(thisCase, OpCodes.Br, defaultLabel);
+                return;
+            }
+
+            /*
+             * Determine where to jump if switch value is lower than lower case value.
+             */
+            ScriptMyLabel lowerLabel = defaultLabel;
+            if(thisCase.lowerCase != null)
+            {
+                lowerLabel = ilGen.DefineLabel("lower");
+            }
+
+            /*
+             * If single case value, put comparison result in this temp.
+             */
+            CompValuTemp cmpv1 = null;
+            if(thisCase.str1 == thisCase.str2)
+            {
+                cmpv1 = new CompValuTemp(tokenTypeInt, this);
+            }
+
+            /*
+             * If switch value .lt. lower case value, jump to lower label.
+             * Maybe save comparison result in a temp.
+             */
+            testRVal.PushVal(this, thisCase, tokenTypeStr);
+            ilGen.Emit(thisCase, OpCodes.Ldstr, thisCase.str1);
+            ilGen.Emit(thisCase, OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
+            ilGen.Emit(thisCase, OpCodes.Call, stringCompareMethodInfo);
+            if(cmpv1 != null)
+            {
+                ilGen.Emit(thisCase, OpCodes.Dup);
+                cmpv1.Pop(this, thisCase);
+            }
+            ilGen.Emit(thisCase, OpCodes.Ldc_I4_0);
+            ilGen.Emit(thisCase, OpCodes.Blt, lowerLabel);
+
+            /*
+             * If switch value .le. higher case value, jump to case code.
+             * Maybe get comparison from the temp.
+             */
+            if(cmpv1 == null)
+            {
+                testRVal.PushVal(this, thisCase, tokenTypeStr);
+                ilGen.Emit(thisCase, OpCodes.Ldstr, thisCase.str2);
+                ilGen.Emit(thisCase, OpCodes.Ldc_I4, (int)StringComparison.Ordinal);
+                ilGen.Emit(thisCase, OpCodes.Call, stringCompareMethodInfo);
+            }
+            else
+            {
+                cmpv1.PushVal(this, thisCase);
+            }
+            ilGen.Emit(thisCase, OpCodes.Ldc_I4_0);
+            ilGen.Emit(thisCase, OpCodes.Ble, thisCase.label);
+
+            /*
+             * Output code for higher comparison if any.
+             */
+            if(thisCase.higherCase == null)
+            {
+                ilGen.Emit(thisCase, OpCodes.Br, defaultLabel);
+            }
+            else
+            {
+                OutputStrCase(testRVal, thisCase.higherCase, defaultLabel);
+            }
+
+            /*
+             * Output code for lower comparison if any.
+             */
+            if(thisCase.lowerCase != null)
+            {
+                ilGen.MarkLabel(lowerLabel);
+                OutputStrCase(testRVal, thisCase.lowerCase, defaultLabel);
+            }
+        }
+
+        /**
+         * @brief output code for a throw statement.
+         * @param throwStmt = throw statement token, including value to be thrown
+         */
+        private void GenerateStmtThrow(TokenStmtThrow throwStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * 'throw' statements never fall through.
+             */
+            mightGetHere = false;
+
+            /*
+             * Output code for either a throw or a rethrow.
+             */
+            if(throwStmt.rVal == null)
+            {
+                for(TokenStmtBlock blk = curStmtBlock; blk != null; blk = blk.outerStmtBlock)
+                {
+                    if(curStmtBlock.isCatch)
+                    {
+                        ilGen.Emit(throwStmt, OpCodes.Rethrow);
+                        return;
+                    }
+                }
+                ErrorMsg(throwStmt, "rethrow allowed only in catch clause");
+            }
+            else
+            {
+                CompValu rVal = GenerateFromRVal(throwStmt.rVal);
+                rVal.PushVal(this, throwStmt.rVal, tokenTypeObj);
+                ilGen.Emit(throwStmt, OpCodes.Call, thrownExceptionWrapMethodInfo);
+                ilGen.Emit(throwStmt, OpCodes.Throw);
+            }
+        }
+
+        /**
+         * @brief output code for a try/catch/finally block
+         */
+        private void GenerateStmtTry(TokenStmtTry tryStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            /*
+             * Reducer should make sure we have exactly one of catch or finally.
+             */
+            if((tryStmt.catchStmt == null) && (tryStmt.finallyStmt == null))
+            {
+                throw new Exception("must have a catch or a finally on try");
+            }
+            if((tryStmt.catchStmt != null) && (tryStmt.finallyStmt != null))
+            {
+                throw new Exception("can't have both catch and finally on same try");
+            }
+
+            /*
+             * Stack the call labels.
+             * Try blocks have their own series of call labels.
+             */
+            ScriptMyLocal saveCallNo = actCallNo;
+            LinkedList<CallLabel> saveCallLabels = actCallLabels;
+
+            /*
+             * Generate code for either try { } catch { } or try { } finally { }.
+             */
+            if(tryStmt.catchStmt != null)
+                GenerateStmtTryCatch(tryStmt);
+            if(tryStmt.finallyStmt != null)
+                GenerateStmtTryFinally(tryStmt);
+
+            /*
+             * Restore call labels.
+             */
+            actCallNo = saveCallNo;
+            actCallLabels = saveCallLabels;
+        }
+
+
+        /**
+         * @brief output code for a try/catch block
+         *
+         *      int    __tryCallNo = -1;                                   // call number within try { } subblock
+         *      int    __catCallNo = -1;                                   // call number within catch { } subblock
+         *      Exception __catThrown = null;                              // caught exception
+         *    <oldCallLabel>:                                              // the outside world jumps here to restore us no matter ...
+         *      try {                                                      // ... where we actually were inside of try/catch
+         *          if (__tryCallNo >= 0) goto tryCallSw;                  // maybe go do restore
+         *          <try body using __tryCallNo>                           // execute script-defined code
+         *                                                                 // ...stack capture WILL run catch { } subblock
+         *          leave tryEnd;                                          // exits
+         *        tryThrow:<tryCallLabel>:
+         *          throw new ScriptRestoreCatchException(__catThrown);    // catch { } was running, jump to its beginning
+         *        tryCallSw:                                               // restoring...
+         *          switch (__tryCallNo) back up into <try body>           // not catching, jump back inside try
+         *      } catch (Exception exc) {
+         *          exc = ScriptRestoreCatchException.Unwrap(exc);         // unwrap possible ScriptRestoreCatchException
+         *          if (exc == null) goto catchRetro;                      // rethrow if IXMRUncatchable (eg, StackCaptureException)
+         *          __catThrown = exc;                                     // save what was thrown so restoring try { } will throw it again
+         *          catchVar = exc;                                        // set up script-visible variable
+         *          __tryCallNo = tryThrow:<tryCallLabel>
+         *          if (__catCallNo >= 0) goto catchCallSw;                // if restoring, go check below
+         *          <catch body using __catCallNo>                         // normal, execute script-defined code
+         *          leave tryEnd;                                          // all done, exit catch { }
+         *        catchRetro:
+         *          rethrow;
+         *        catchCallSw:
+         *          switch (__catCallNo) back up into <catch body>         // restart catch { } code wherever it was
+         *      }
+         *    tryEnd:
+         */
+        private void GenerateStmtTryCatch(TokenStmtTry tryStmt)
+        {
+            CompValuTemp tryCallNo = new CompValuTemp(tokenTypeInt, this);
+            CompValuTemp catCallNo = new CompValuTemp(tokenTypeInt, this);
+            CompValuTemp catThrown = new CompValuTemp(tokenTypeExc, this);
+
+            ScriptMyLabel tryCallSw = ilGen.DefineLabel("__tryCallSw_" + tryStmt.Unique);
+            ScriptMyLabel catchRetro = ilGen.DefineLabel("__catchRetro_" + tryStmt.Unique);
+            ScriptMyLabel catchCallSw = ilGen.DefineLabel("__catchCallSw_" + tryStmt.Unique);
+            ScriptMyLabel tryEnd = ilGen.DefineLabel("__tryEnd_" + tryStmt.Unique);
+
+            SetCallNo(tryStmt, tryCallNo, -1);
+            SetCallNo(tryStmt, catCallNo, -1);
+            ilGen.Emit(tryStmt, OpCodes.Ldnull);
+            catThrown.Pop(this, tryStmt);
+
+            new CallLabel(this, tryStmt);              //   <oldcalllabel>:
+            ilGen.BeginExceptionBlock();               //     try {
+            openCallLabel = null;
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "enter try*: " + tryStmt.line + " callMode=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                PushXMRInst();
+                ilGen.Emit(tryStmt, OpCodes.Ldfld, callModeFieldInfo);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " tryCallNo=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                tryCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " catThrown.IsNull=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catThrown.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Ldnull);
+                ilGen.Emit(tryStmt, OpCodes.Ceq);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " catCallNo=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            GetCallNo(tryStmt, tryCallNo);             //         if (__tryCallNo >= 0) goto tryCallSw;
+            ilGen.Emit(tryStmt, OpCodes.Ldc_I4_0);
+            ilGen.Emit(tryStmt, OpCodes.Bge, tryCallSw);
+
+            actCallNo = tryCallNo.localBuilder;                     // set up __tryCallNo for call labels
+            actCallLabels = new LinkedList<CallLabel>();
+
+            GenerateStmtBlock(tryStmt.tryStmt);            // output the try block statement subblock
+
+            bool tryBlockFallsOutBottom = mightGetHere;
+            if(tryBlockFallsOutBottom)
+            {
+                new CallLabel(this, tryStmt);          //       <tryCallLabel>:
+                ilGen.Emit(tryStmt, OpCodes.Leave, tryEnd);    //         leave tryEnd;
+                openCallLabel = null;
+            }
+
+            CallLabel tryThrow = new CallLabel(this, tryStmt); //       tryThrow:<tryCallLabel>:
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "tryThrow*: " + tryStmt.line + " catThrown=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catThrown.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+            catThrown.PushVal(this, tryStmt);          //         throw new ScriptRestoreCatchException (__catThrown);
+            ilGen.Emit(tryStmt, OpCodes.Newobj, scriptRestoreCatchExceptionConstructorInfo);
+            ilGen.Emit(tryStmt, OpCodes.Throw);
+            openCallLabel = null;
+
+            ilGen.MarkLabel(tryCallSw);                //       tryCallSw:
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "tryCallSw*: " + tryStmt.line + " tryCallNo=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                tryCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+            OutputCallNoSwitchStmt();              //         switch (tryCallNo) ...
+
+            CompValuLocalVar catchVarLocExc = null;
+            CompValuTemp catchVarLocStr = null;
+
+            if(tryStmt.catchVar.type.ToSysType() == typeof(Exception))
+            {
+                catchVarLocExc = new CompValuLocalVar(tryStmt.catchVar.type, tryStmt.catchVar.name.val, this);
+            }
+            else if(tryStmt.catchVar.type.ToSysType() == typeof(String))
+            {
+                catchVarLocStr = new CompValuTemp(tryStmt.catchVar.type, this);
+            }
+
+            ScriptMyLocal excLocal = ilGen.DeclareLocal(typeof(String), "catchstr_" + tryStmt.Unique);
+
+            ilGen.BeginCatchBlock(typeof(Exception));     // start of the catch block that can catch any exception
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldstr, "enter catch*: " + tryStmt.line + " callMode=");
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                PushXMRInst();
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldfld, callModeFieldInfo);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldstr, " catCallNo=");
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldstr, " exc=");
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Dup);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, scriptRestoreCatchExceptionUnwrap);
+            // exc = ScriptRestoreCatchException.Unwrap (exc);
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Dup);        // rethrow if IXMRUncatchable (eg, StackCaptureException)
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Brfalse, catchRetro);
+            if(tryStmt.catchVar.type.ToSysType() == typeof(Exception))
+            {
+                tryStmt.catchVar.location = catchVarLocExc;
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Dup);
+                catThrown.Pop(this, tryStmt);              // store exception object in catThrown
+                catchVarLocExc.Pop(this, tryStmt.catchVar.name);      // also store in script-visible variable
+            }
+            else if(tryStmt.catchVar.type.ToSysType() == typeof(String))
+            {
+                tryStmt.catchVar.location = catchVarLocStr;
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Dup);
+                catThrown.Pop(this, tryStmt);              // store exception object in catThrown
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Call, catchExcToStrMethodInfo);
+
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Stloc, excLocal);
+                catchVarLocStr.PopPre(this, tryStmt.catchVar.name);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldloc, excLocal);
+                catchVarLocStr.PopPost(this, tryStmt.catchVar.name, tokenTypeStr);
+            }
+            else
+            {
+                throw new Exception("bad catch var type " + tryStmt.catchVar.type.ToString());
+            }
+
+            SetCallNo(tryStmt, tryCallNo, tryThrow.index);     // __tryCallNo = tryThrow so it knows to do 'throw catThrown' on restore
+
+            GetCallNo(tryStmt, catCallNo);             // if (__catCallNo >= 0) goto catchCallSw;
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Ldc_I4_0);
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Bge, catchCallSw);
+
+            actCallNo = catCallNo.localBuilder;                 // set up __catCallNo for call labels
+            actCallLabels.Clear();
+            mightGetHere = true;                    // if we can get to the 'try' assume we can get to the 'catch'
+            GenerateStmtBlock(tryStmt.catchStmt);          // output catch clause statement subblock
+
+            if(mightGetHere)
+            {
+                new CallLabel(this, tryStmt.catchStmt);
+                ilGen.Emit(tryStmt.catchStmt, OpCodes.Leave, tryEnd);
+                openCallLabel = null;
+            }
+
+            ilGen.MarkLabel(catchRetro);               // not a script-visible exception, rethrow it
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Pop);
+            ilGen.Emit(tryStmt.catchStmt, OpCodes.Rethrow);
+
+            ilGen.MarkLabel(catchCallSw);
+            OutputCallNoSwitchStmt();              // restoring, jump back inside script-defined body
+
+            ilGen.EndExceptionBlock();
+            ilGen.MarkLabel(tryEnd);
+
+            mightGetHere |= tryBlockFallsOutBottom;         // also get here if try body falls out bottom
+        }
+
+        /**
+         * @brief output code for a try/finally block
+         *
+         * This is such a mess because there is hidden state for the finally { } that we have to recreate.
+         * The finally { } can be entered either via an exception being thrown in the try { } or a leave 
+         * being executed in the try { } whose target is outside the try { } finally { }.
+         *
+         * For the thrown exception case, we slip in a try { } catch { } wrapper around the original try { }
+         * body.  This will sense any thrown exception that would execute the finally { }.  Then we have our
+         * try { } throw the exception on restore which gets the finally { } called and on its way again.
+         *
+         * For the leave case, we prefix all leave instructions with a call label and we explicitly chain
+         * all leaves through each try { } that has an associated finally { } that the leave would unwind 
+         * through.  This gets each try { } to simply jump to the correct leave instruction which immediately 
+         * invokes the corresponding finally { } and then chains to the next leave instruction on out until 
+         * it gets to its target.
+         *
+         *      int    __finCallNo = -1;                                     // call number within finally { } subblock
+         *      int    __tryCallNo = -1;                                     // call number within try { } subblock
+         *      Exception __catThrown = null;                                // caught exception
+         *    <oldCallLabel>:                                                // the outside world jumps here to restore us no matter ...
+         *      try {                                                        // ... where we actually were inside of try/finally
+         *          try {
+         *              if (__tryCallNo >= 0) goto tryCallSw;                // maybe go do restore
+         *              <try body using __tryCallNo>                         // execute script-defined code
+         *                                                                   // ...stack capture WILL run catch/finally { } subblock
+         *              leave tryEnd;                                        // executes finally { } subblock and exits
+         *            tryThrow:<tryCallLabel>:
+         *              throw new ScriptRestoreCatchException(__catThrown);  // catch { } was running, jump to its beginning
+         *            tryCallSw:                                             // restoring...
+         *              switch (__tryCallNo) back up into <try body>         // jump back inside try, ...
+         *                                                                   // ... maybe to a leave if we were doing finally { } subblock
+         *          } catch (Exception exc) {                                // in case we're getting to finally { } via a thrown exception:
+         *              exc = ScriptRestoreCatchException.Unwrap(exc);       // unwrap possible ScriptRestoreCatchException
+         *              if (callMode == CallMode_SAVE) goto catchRetro;      // don't touch anything if capturing stack
+         *              __catThrown = exc;                                   // save exception so try { } can throw it on restore
+         *              __tryCallNo = tryThrow:<tryCallLabel>;               // tell try { } to throw it on restore
+         *            catchRetro:
+         *              rethrow;                                             // in any case, go on to finally { } subblock now
+         *          }
+         *      } finally {
+         *          if (callMode == CallMode_SAVE) goto finEnd;              // don't touch anything if capturing stack
+         *          if (__finCallNo >= 0) goto finCallSw;                    // maybe go do restore
+         *          <finally body using __finCallNo>                         // normal, execute script-defined code
+         *        finEnd:
+         *          endfinally                                               // jump to leave/throw target or next outer finally { }
+         *        finCallSw:
+         *          switch (__finCallNo) back up into <finally body>         // restoring, restart finally { } code wherever it was
+         *      }
+         *    tryEnd:
+         */
+        private void GenerateStmtTryFinally(TokenStmtTry tryStmt)
+        {
+            CompValuTemp finCallNo = new CompValuTemp(tokenTypeInt, this);
+            CompValuTemp tryCallNo = new CompValuTemp(tokenTypeInt, this);
+            CompValuTemp catThrown = new CompValuTemp(tokenTypeExc, this);
+
+            ScriptMyLabel tryCallSw = ilGen.DefineLabel("__tryCallSw_" + tryStmt.Unique);
+            ScriptMyLabel catchRetro = ilGen.DefineLabel("__catchRetro_" + tryStmt.Unique);
+            ScriptMyLabel finCallSw = ilGen.DefineLabel("__finCallSw_" + tryStmt.Unique);
+            BreakContTarg finEnd = new BreakContTarg(this, "__finEnd_" + tryStmt.Unique);
+            ScriptMyLabel tryEnd = ilGen.DefineLabel("__tryEnd_" + tryStmt.Unique);
+
+            SetCallNo(tryStmt, finCallNo, -1);
+            SetCallNo(tryStmt, tryCallNo, -1);
+            ilGen.Emit(tryStmt, OpCodes.Ldnull);
+            catThrown.Pop(this, tryStmt);
+
+            new CallLabel(this, tryStmt);              //   <oldcalllabel>:
+            ilGen.BeginExceptionBlock();               //     try {
+            ilGen.BeginExceptionBlock();               //     try {
+            openCallLabel = null;
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "enter try*: " + tryStmt.line + " callMode=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                PushXMRInst();
+                ilGen.Emit(tryStmt, OpCodes.Ldfld, callModeFieldInfo);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " tryCallNo=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                tryCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " finCallNo=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                finCallNo.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " catThrown.IsNull=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catThrown.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Ldnull);
+                ilGen.Emit(tryStmt, OpCodes.Ceq);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+
+            GetCallNo(tryStmt, tryCallNo);             //         if (__tryCallNo >= 0) goto tryCallSw;
+            ilGen.Emit(tryStmt, OpCodes.Ldc_I4_0);
+            ilGen.Emit(tryStmt, OpCodes.Bge, tryCallSw);
+
+            actCallNo = tryCallNo.localBuilder;                     // set up __tryCallNo for call labels
+            actCallLabels = new LinkedList<CallLabel>();
+
+            GenerateStmtBlock(tryStmt.tryStmt);            // output the try block statement subblock
+
+            if(mightGetHere)
+            {
+                new CallLabel(this, tryStmt);          //       <newCallLabel>:
+                ilGen.Emit(tryStmt, OpCodes.Leave, tryEnd);    //         leave tryEnd;
+                openCallLabel = null;
+            }
+
+            foreach(IntermediateLeave iLeave in tryStmt.iLeaves.Values)
+            {
+                ilGen.MarkLabel(iLeave.jumpIntoLabel);     //       intr2_exit:
+                new CallLabel(this, tryStmt);          //         tryCallNo = n;
+                ilGen.Emit(tryStmt, OpCodes.Leave, iLeave.jumpAwayLabel);  //    __callNo_n_: leave int1_exit;
+                openCallLabel = null;
+            }
+
+            CallLabel tryThrow = new CallLabel(this, tryStmt); //       tryThrow:<tryCallLabel>:
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "tryThrow*: " + tryStmt.line + " catThrown=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                catThrown.PushVal(this, tryStmt);
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+            catThrown.PushVal(this, tryStmt);          //         throw new ScriptRestoreCatchException (__catThrown);
+            ilGen.Emit(tryStmt, OpCodes.Newobj, scriptRestoreCatchExceptionConstructorInfo);
+            ilGen.Emit(tryStmt, OpCodes.Throw);
+            openCallLabel = null;
+
+            ilGen.MarkLabel(tryCallSw);                //       tryCallSw:
+            OutputCallNoSwitchStmt();              //         switch (tryCallNo) ...
+                                                   //     }
+
+            ilGen.BeginCatchBlock(typeof(Exception));     // start of the catch block that can catch any exception
+            if(DEBUG_TRYSTMT)
+            {
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "enter catch*: " + tryStmt.line + " callMode=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                PushXMRInst();
+                ilGen.Emit(tryStmt, OpCodes.Ldfld, callModeFieldInfo);
+                ilGen.Emit(tryStmt, OpCodes.Box, typeof(int));
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, " exc=");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Dup);
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+                ilGen.Emit(tryStmt, OpCodes.Ldstr, "\n");
+                ilGen.Emit(tryStmt, OpCodes.Call, consoleWriteMethodInfo);
+            }
+            ilGen.Emit(tryStmt, OpCodes.Call, scriptRestoreCatchExceptionUnwrap);  // exc = ScriptRestoreCatchException.Unwrap (exc);
+            PushXMRInst();                     // if (callMode == CallMode_SAVE) goto catchRetro;
+            ilGen.Emit(tryStmt, OpCodes.Ldfld, callModeFieldInfo);
+            ilGen.Emit(tryStmt, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
+            ilGen.Emit(tryStmt, OpCodes.Beq, catchRetro);
+
+            catThrown.Pop(this, tryStmt);              // __catThrown = exc;
+            SetCallNo(tryStmt, tryCallNo, tryThrow.index);     // __tryCallNo = tryThrow:<tryCallLabel>;
+            ilGen.Emit(tryStmt, OpCodes.Rethrow);
+
+            ilGen.MarkLabel(catchRetro);               // catchRetro:
+            ilGen.Emit(tryStmt, OpCodes.Pop);
+            ilGen.Emit(tryStmt, OpCodes.Rethrow);          //    rethrow;
+
+            ilGen.EndExceptionBlock();             // }
+
+            ilGen.BeginFinallyBlock();             // start of the finally block
+
+            PushXMRInst();                     // if (callMode == CallMode_SAVE) goto finEnd;
+            ilGen.Emit(tryStmt, OpCodes.Ldfld, callModeFieldInfo);
+            ilGen.Emit(tryStmt, OpCodes.Ldc_I4, XMRInstAbstract.CallMode_SAVE);
+            ilGen.Emit(tryStmt, OpCodes.Beq, finEnd.label);
+
+            GetCallNo(tryStmt, finCallNo);             // if (__finCallNo >= 0) goto finCallSw;
+            ilGen.Emit(tryStmt, OpCodes.Ldc_I4_0);
+            ilGen.Emit(tryStmt, OpCodes.Bge, finCallSw);
+
+            actCallNo = finCallNo.localBuilder;                 // set up __finCallNo for call labels
+            actCallLabels.Clear();
+            mightGetHere = true;                    // if we can get to the 'try' assume we can get to the 'finally'
+            GenerateStmtBlock(tryStmt.finallyStmt);        // output finally clause statement subblock
+
+            ilGen.MarkLabel(finEnd.label);             // finEnd:
+            ilGen.Emit(tryStmt, OpCodes.Endfinally);       //    return out to next finally { } or catch { } or leave target
+
+            ilGen.MarkLabel(finCallSw);                // restore mode, switch (finCallNo) ...
+            OutputCallNoSwitchStmt();
+
+            ilGen.EndExceptionBlock();
+            ilGen.MarkLabel(tryEnd);
+
+            mightGetHere |= finEnd.used;                // get here if finally body falls through or has a break statement
+        }
+
+        /**
+         * @brief Generate code to initialize a variable to its default value.
+         */
+        private void GenerateStmtVarIniDef(TokenStmtVarIniDef varIniDefStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            CompValu left = GenerateFromLVal(varIniDefStmt.var);
+            left.PopPre(this, varIniDefStmt);
+            PushDefaultValue(left.type);
+            left.PopPost(this, varIniDefStmt);
+        }
+
+        /**
+         * @brief generate code for a 'while' statement including the loop body.
+         */
+        private void GenerateStmtWhile(TokenStmtWhile whileStmt)
+        {
+            if(!mightGetHere)
+                return;
+
+            BreakContTarg oldBreakTarg = curBreakTarg;
+            BreakContTarg oldContTarg = curContTarg;
+            ScriptMyLabel loopLabel = ilGen.DefineLabel("whileloop_" + whileStmt.Unique);
+
+            curBreakTarg = new BreakContTarg(this, "whilebreak_" + whileStmt.Unique);
+            curContTarg = new BreakContTarg(this, "whilecont_" + whileStmt.Unique);
+
+            ilGen.MarkLabel(loopLabel);                                          // loop:
+            CompValu testRVal = GenerateFromRVal(whileStmt.testRVal);            //   testRVal = while test expression
+            if(!IsConstBoolExprTrue(testRVal))
+            {
+                testRVal.PushVal(this, whileStmt.testRVal, tokenTypeBool);   //   if (!testRVal)
+                ilGen.Emit(whileStmt, OpCodes.Brfalse, curBreakTarg.label);  //      goto break
+                curBreakTarg.used = true;
+            }
+            GenerateStmt(whileStmt.bodyStmt);                                    //   while body statement
+            if(curContTarg.used)
+            {
+                ilGen.MarkLabel(curContTarg.label);                          // cont:
+                mightGetHere = true;
+            }
+            if(mightGetHere)
+            {
+                EmitCallCheckRun(whileStmt, false);                          //   __sw.CheckRun()
+                ilGen.Emit(whileStmt, OpCodes.Br, loopLabel);                //   goto loop
+            }
+            mightGetHere = curBreakTarg.used;
+            if(mightGetHere)
+            {
+                ilGen.MarkLabel(curBreakTarg.label);                         // done:
+            }
+
+            curBreakTarg = oldBreakTarg;
+            curContTarg = oldContTarg;
+        }
+
+        /**
+         * @brief process a local variable declaration statement, possibly with initialization expression.
+         *        Note that the function header processing allocated stack space (CompValuTemp) for the
+         *        variable and now all we do is write its initialization value.
+         */
+        private void GenerateDeclVar(TokenDeclVar declVar)
+        {
+            /*
+             * Script gave us an initialization value, so just store init value in var like an assignment statement.
+             * If no init given, set it to its default value.
+             */
+            CompValu local = declVar.location;
+            if(declVar.init != null)
+            {
+                CompValu rVal = GenerateFromRVal(declVar.init, local.GetArgTypes());
+                local.PopPre(this, declVar);
+                rVal.PushVal(this, declVar.init, declVar.type);
+                local.PopPost(this, declVar);
+            }
+            else
+            {
+                local.PopPre(this, declVar);
+                PushDefaultValue(declVar.type);
+                local.PopPost(this, declVar);
+            }
+        }
+
+        /**
+         * @brief Get the type and location of an L-value (eg, variable)
+         * @param lVal    = L-value expression to evaluate
+         * @param argsig  = null: it's a field/property
+         *                  else: select overload method that fits these arg types
+         */
+        private CompValu GenerateFromLVal(TokenLVal lVal)
+        {
+            return GenerateFromLVal(lVal, null);
+        }
+        private CompValu GenerateFromLVal(TokenLVal lVal, TokenType[] argsig)
+        {
+            if(lVal is TokenLValArEle)
+                return GenerateFromLValArEle((TokenLValArEle)lVal);
+            if(lVal is TokenLValBaseField)
+                return GenerateFromLValBaseField((TokenLValBaseField)lVal, argsig);
+            if(lVal is TokenLValIField)
+                return GenerateFromLValIField((TokenLValIField)lVal, argsig);
+            if(lVal is TokenLValName)
+                return GenerateFromLValName((TokenLValName)lVal, argsig);
+            if(lVal is TokenLValSField)
+                return GenerateFromLValSField((TokenLValSField)lVal, argsig);
+            throw new Exception("bad lval class");
+        }
+
+        /**
+         * @brief we have an L-value token that is an element within an array.
+         * @returns a CompValu giving the type and location of the element of the array.
+         */
+        private CompValu GenerateFromLValArEle(TokenLValArEle lVal)
+        {
+            CompValu subCompValu;
+
+            /*
+             * Compute location of array itself.
+             */
+            CompValu baseCompValu = GenerateFromRVal(lVal.baseRVal);
+
+            /*
+             * Maybe it is a fixed array access.
+             */
+            string basetypestring = baseCompValu.type.ToString();
+            if(basetypestring.EndsWith("]"))
+            {
+                TokenRVal subRVal = lVal.subRVal;
+                int nSubs = 1;
+                if(subRVal is TokenRValList)
+                {
+                    nSubs = ((TokenRValList)subRVal).nItems;
+                    subRVal = ((TokenRValList)subRVal).rVal;
+                }
+
+                int rank = basetypestring.IndexOf(']') - basetypestring.IndexOf('[');
+                if(nSubs != rank)
+                {
+                    ErrorMsg(lVal.baseRVal, "expect " + rank + " subscript" + ((rank == 1) ? "" : "s") + " but have " + nSubs);
+                }
+                CompValu[] subCompValus = new CompValu[rank];
+                int i;
+                for(i = 0; (subRVal != null) && (i < rank); i++)
+                {
+                    subCompValus[i] = GenerateFromRVal(subRVal);
+                    subRVal = (TokenRVal)subRVal.nextToken;
+                }
+                while(i < rank)
+                    subCompValus[i++] = new CompValuInteger(new TokenTypeInt(lVal.subRVal), 0);
+                return new CompValuFixArEl(this, baseCompValu, subCompValus);
+            }
+
+            /*
+             * Maybe it is accessing the $idxprop property of a script-defined class.
+             */
+            if(baseCompValu.type is TokenTypeSDTypeClass)
+            {
+                TokenName name = new TokenName(lVal, "$idxprop");
+                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseCompValu.type;
+                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+                TokenDeclVar idxProp = FindThisMember(sdtDecl, name, null);
+                if(idxProp == null)
+                {
+                    ErrorMsg(lVal, "no index property in class " + sdtDecl.longName.val);
+                    return new CompValuVoid(lVal);
+                }
+                if((idxProp.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+                {
+                    ErrorMsg(lVal, "non-static reference to static member " + idxProp.name.val);
+                    return new CompValuVoid(idxProp);
+                }
+                CheckAccess(idxProp, name);
+
+                TokenType[] argTypes = IdxPropArgTypes(idxProp);
+                CompValu[] compValus = IdxPropCompValus(lVal, argTypes.Length);
+                return new CompValuIdxProp(idxProp, baseCompValu, argTypes, compValus);
+
+            }
+
+            /*
+             * Maybe they are accessing $idxprop property of a script-defined interface.
+             */
+            if(baseCompValu.type is TokenTypeSDTypeInterface)
+            {
+                TokenName name = new TokenName(lVal, "$idxprop");
+                TokenTypeSDTypeInterface sdtType = (TokenTypeSDTypeInterface)baseCompValu.type;
+                TokenDeclVar idxProp = FindInterfaceMember(sdtType, name, null, ref baseCompValu);
+                if(idxProp == null)
+                {
+                    ErrorMsg(lVal, "no index property defined for interface " + sdtType.decl.longName.val);
+                    return baseCompValu;
+                }
+
+                TokenType[] argTypes = IdxPropArgTypes(idxProp);
+                CompValu[] compValus = IdxPropCompValus(lVal, argTypes.Length);
+                return new CompValuIdxProp(idxProp, baseCompValu, argTypes, compValus);
+            }
+
+            /*
+             * Maybe it is extracting a character from a string.
+             */
+            if((baseCompValu.type is TokenTypeKey) || (baseCompValu.type is TokenTypeStr))
+            {
+                subCompValu = GenerateFromRVal(lVal.subRVal);
+                return new CompValuStrChr(new TokenTypeChar(lVal), baseCompValu, subCompValu);
+            }
+
+            /*
+             * Maybe it is extracting an element from a list.
+             */
+            if(baseCompValu.type is TokenTypeList)
+            {
+                subCompValu = GenerateFromRVal(lVal.subRVal);
+                return new CompValuListEl(new TokenTypeObject(lVal), baseCompValu, subCompValu);
+            }
+
+            /*
+             * Access should be to XMR_Array otherwise.
+             */
+            if(!(baseCompValu.type is TokenTypeArray))
+            {
+                ErrorMsg(lVal, "taking subscript of non-array");
+                return baseCompValu;
+            }
+            subCompValu = GenerateFromRVal(lVal.subRVal);
+            return new CompValuArEle(new TokenTypeObject(lVal), baseCompValu, subCompValu);
+        }
+
+        /**
+         * @brief Get number and type of arguments required by an index property.
+         */
+        private static TokenType[] IdxPropArgTypes(TokenDeclVar idxProp)
+        {
+            TokenType[] argTypes;
+            if(idxProp.getProp != null)
+            {
+                int nArgs = idxProp.getProp.argDecl.varDict.Count;
+                argTypes = new TokenType[nArgs];
+                foreach(TokenDeclVar var in idxProp.getProp.argDecl.varDict)
+                {
+                    argTypes[var.vTableIndex] = var.type;
+                }
+            }
+            else
+            {
+                int nArgs = idxProp.setProp.argDecl.varDict.Count - 1;
+                argTypes = new TokenType[nArgs];
+                foreach(TokenDeclVar var in idxProp.setProp.argDecl.varDict)
+                {
+                    if(var.vTableIndex < nArgs)
+                    {
+                        argTypes[var.vTableIndex] = var.type;
+                    }
+                }
+            }
+            return argTypes;
+        }
+
+        /**
+         * @brief Get number and computed value of index property arguments.
+         * @param lVal = list of arguments
+         * @param nArgs = number of arguments required
+         * @returns null: argument count mismatch
+         *          else: array of index property argument values
+         */
+        private CompValu[] IdxPropCompValus(TokenLValArEle lVal, int nArgs)
+        {
+            TokenRVal subRVal = lVal.subRVal;
+            int nSubs = 1;
+            if(subRVal is TokenRValList)
+            {
+                nSubs = ((TokenRValList)subRVal).nItems;
+                subRVal = ((TokenRValList)subRVal).rVal;
+            }
+
+            if(nSubs != nArgs)
+            {
+                ErrorMsg(lVal, "index property requires " + nArgs + " subscript(s)");
+                return null;
+            }
+
+            CompValu[] subCompValus = new CompValu[nArgs];
+            for(int i = 0; i < nArgs; i++)
+            {
+                subCompValus[i] = GenerateFromRVal(subRVal);
+                subRVal = (TokenRVal)subRVal.nextToken;
+            }
+            return subCompValus;
+        }
+
+        /**
+         * @brief using 'base' within a script-defined instance method to refer to an instance field/method 
+         *        of the class being extended.
+         */
+        private CompValu GenerateFromLValBaseField(TokenLValBaseField baseField, TokenType[] argsig)
+        {
+            string fieldName = baseField.fieldName.val;
+
+            TokenDeclSDType sdtDecl = curDeclFunc.sdtClass;
+            if((sdtDecl == null) || ((curDeclFunc.sdtFlags & ScriptReduce.SDT_STATIC) != 0))
+            {
+                ErrorMsg(baseField, "cannot use 'base' outside instance method body");
+                return new CompValuVoid(baseField);
+            }
+            if(!IsSDTInstMethod())
+            {
+                ErrorMsg(baseField, "cannot access instance member of base class from static method");
+                return new CompValuVoid(baseField);
+            }
+
+            TokenDeclVar declVar = FindThisMember(sdtDecl.extends, baseField.fieldName, argsig);
+            if(declVar != null)
+            {
+                CheckAccess(declVar, baseField.fieldName);
+                TokenType baseType = declVar.sdtClass.MakeRefToken(baseField);
+                CompValu basePtr = new CompValuArg(baseType, 0);
+                return AccessInstanceMember(declVar, basePtr, baseField, true);
+            }
+
+            ErrorMsg(baseField, "no member " + fieldName + ArgSigString(argsig) + " rootward of " + sdtDecl.longName.val);
+            return new CompValuVoid(baseField);
+        }
+
+        /**
+         * @brief We have an L-value token that is an instance field/method within a struct.
+         * @returns a CompValu giving the type and location of the field/method in the struct.
+         */
+        private CompValu GenerateFromLValIField(TokenLValIField lVal, TokenType[] argsig)
+        {
+            CompValu baseRVal = GenerateFromRVal(lVal.baseRVal);
+            string fieldName = lVal.fieldName.val + ArgSigString(argsig);
+
+            /*
+             * Maybe they are accessing an instance field, method or property of a script-defined class.
+             */
+            if(baseRVal.type is TokenTypeSDTypeClass)
+            {
+                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
+                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+                TokenDeclVar declVar = FindThisMember(sdtDecl, lVal.fieldName, argsig);
+                if(declVar != null)
+                {
+                    CheckAccess(declVar, lVal.fieldName);
+                    return AccessInstanceMember(declVar, baseRVal, lVal, false);
+                }
+                ErrorMsg(lVal.fieldName, "no member " + fieldName + " in class " + sdtDecl.longName.val);
+                return new CompValuVoid(lVal.fieldName);
+            }
+
+            /*
+             * Maybe they are accessing a method or property of a script-defined interface.
+             */
+            if(baseRVal.type is TokenTypeSDTypeInterface)
+            {
+                TokenTypeSDTypeInterface sdtType = (TokenTypeSDTypeInterface)baseRVal.type;
+                TokenDeclVar declVar = FindInterfaceMember(sdtType, lVal.fieldName, argsig, ref baseRVal);
+                if(declVar != null)
+                {
+                    return new CompValuIntfMember(declVar, baseRVal);
+                }
+                ErrorMsg(lVal.fieldName, "no member " + fieldName + " in interface " + sdtType.decl.longName.val);
+                return new CompValuVoid(lVal.fieldName);
+            }
+
+            /*
+             * Since we only have a few built-in types with fields, just pound them out.
+             */
+            if(baseRVal.type is TokenTypeArray)
+            {
+
+                // no arguments, no parentheses, just the field name, returning integer
+                // but internally, it is a call to a method()
+                if(fieldName == "count")
+                {
+                    return new CompValuIntInstROProp(tokenTypeInt, baseRVal, arrayCountMethodInfo);
+                }
+
+                // no arguments but with the parentheses, returning void
+                if(fieldName == "clear()")
+                {
+                    return new CompValuIntInstMeth(XMR_Array.clearDelegate, baseRVal, arrayClearMethodInfo);
+                }
+
+                // single integer argument, returning an object
+                if(fieldName == "index(integer)")
+                {
+                    return new CompValuIntInstMeth(XMR_Array.indexDelegate, baseRVal, arrayIndexMethodInfo);
+                }
+                if(fieldName == "value(integer)")
+                {
+                    return new CompValuIntInstMeth(XMR_Array.valueDelegate, baseRVal, arrayValueMethodInfo);
+                }
+            }
+            if(baseRVal.type is TokenTypeRot)
+            {
+                FieldInfo fi = null;
+                if(fieldName == "x")
+                    fi = rotationXFieldInfo;
+                if(fieldName == "y")
+                    fi = rotationYFieldInfo;
+                if(fieldName == "z")
+                    fi = rotationZFieldInfo;
+                if(fieldName == "s")
+                    fi = rotationSFieldInfo;
+                if(fi != null)
+                {
+                    return new CompValuField(new TokenTypeFloat(lVal), baseRVal, fi);
+                }
+            }
+            if(baseRVal.type is TokenTypeVec)
+            {
+                FieldInfo fi = null;
+                if(fieldName == "x")
+                    fi = vectorXFieldInfo;
+                if(fieldName == "y")
+                    fi = vectorYFieldInfo;
+                if(fieldName == "z")
+                    fi = vectorZFieldInfo;
+                if(fi != null)
+                {
+                    return new CompValuField(new TokenTypeFloat(lVal), baseRVal, fi);
+                }
+            }
+
+            ErrorMsg(lVal, "type " + baseRVal.type.ToString() + " does not define member " + fieldName);
+            return baseRVal;
+        }
+
+        /**
+         * @brief We have an L-value token that is a function, method or variable name.
+         * @param lVal = name we are looking for
+         * @param argsig = null: just look for name as a variable
+         *                 else: look for name as a function/method being called with the given argument types
+         *                       eg, "(string,integer,list)"
+         * @returns a CompValu giving the type and location of the function, method or variable.
+         */
+        private CompValu GenerateFromLValName(TokenLValName lVal, TokenType[] argsig)
+        {
+            /*
+             * Look in variable stack then look for built-in constants and functions.
+             */
+            TokenDeclVar var = FindNamedVar(lVal, argsig);
+            if(var == null)
+            {
+                ErrorMsg(lVal, "undefined constant/function/variable " + lVal.name.val + ArgSigString(argsig));
+                return new CompValuVoid(lVal);
+            }
+
+            /*
+             * Maybe it has an implied 'this.' on the front.
+             */
+            if((var.sdtClass != null) && ((var.sdtFlags & ScriptReduce.SDT_STATIC) == 0))
+            {
+
+                if(!IsSDTInstMethod())
+                {
+                    ErrorMsg(lVal, "cannot access instance member of class from static method");
+                    return new CompValuVoid(lVal);
+                }
+
+                /*
+                 * Don't allow something such as:
+                 *
+                 *    class A {
+                 *        integer I;
+                 *        class B {
+                 *            Print ()
+                 *            {
+                 *                llOwnerSay ("I=" + (string)I); <- access to I not allowed inside class B.
+                 *                                                  explicit reference required as we don't
+                 *                                                  have a valid reference to class A.
+                 *            }
+                 *        }
+                 *    }
+                 *
+                 * But do allow something such as:
+                 *
+                 *    class A {
+                 *        integer I;
+                 *    }
+                 *    class B : A {
+                 *        Print ()
+                 *        {
+                 *            llOwnerSay ("I=" + (string)I);
+                 *        }
+                 *    }
+                 */
+                for(TokenDeclSDType c = curDeclFunc.sdtClass; c != var.sdtClass; c = c.extends)
+                {
+                    if(c == null)
+                    {
+                        // our arg0 points to an instance of curDeclFunc.sdtClass, not var.sdtClass
+                        ErrorMsg(lVal, "cannot access instance member of outer class with implied 'this'");
+                        break;
+                    }
+                }
+
+                CompValu thisCompValu = new CompValuArg(var.sdtClass.MakeRefToken(lVal), 0);
+                return AccessInstanceMember(var, thisCompValu, lVal, false);
+            }
+
+            /*
+             * It's a local variable, static field, global, constant, etc.
+             */
+            return var.location;
+        }
+
+        /**
+         * @brief Access a script-defined type's instance member
+         * @param declVar = which member (field,method,property) to access
+         * @param basePtr = points to particular object instance
+         * @param ignoreVirt = true: access declVar's method directly; else: maybe use vTable
+         * @returns where the field/method/property is located
+         */
+        private CompValu AccessInstanceMember(TokenDeclVar declVar, CompValu basePtr, Token errorAt, bool ignoreVirt)
+        {
+            if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+            {
+                ErrorMsg(errorAt, "non-static reference to static member " + declVar.name.val);
+                return new CompValuVoid(declVar);
+            }
+            return new CompValuInstMember(declVar, basePtr, ignoreVirt);
+        }
+
+        /**
+         * @brief we have an L-value token that is a static member within a struct.
+         * @returns a CompValu giving the type and location of the member in the struct.
+         */
+        private CompValu GenerateFromLValSField(TokenLValSField lVal, TokenType[] argsig)
+        {
+            TokenType stType = lVal.baseType;
+            string fieldName = lVal.fieldName.val + ArgSigString(argsig);
+
+            /*
+             * Maybe they are accessing a static member of a script-defined class.
+             */
+            if(stType is TokenTypeSDTypeClass)
+            {
+                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)stType;
+                TokenDeclVar declVar = FindThisMember(sdtType.decl, lVal.fieldName, argsig);
+                if(declVar != null)
+                {
+                    CheckAccess(declVar, lVal.fieldName);
+                    if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) == 0)
+                    {
+                        ErrorMsg(lVal.fieldName, "static reference to non-static member " + fieldName);
+                        return new CompValuVoid(lVal.fieldName);
+                    }
+                    return declVar.location;
+                }
+            }
+
+            ErrorMsg(lVal.fieldName, "no member " + fieldName + " in " + stType.ToString());
+            return new CompValuVoid(lVal.fieldName);
+        }
+
+        /**
+         * @brief generate code from an RVal expression and return its type and where the result is stored.
+         * For anything that has side-effects, statements are generated that perform the computation then
+         * the result it put in a temp var and the temp var name is returned.
+         * For anything without side-effects, they are returned as an equivalent sequence of Emits.
+         * @param rVal = rVal token to be evaluated
+         * @param argsig = null: not being used in an function/method context
+         *                 else: string giving argument types, eg, "(string,integer,list,vector)"
+         *                       that can be used to select among overloaded methods
+         * @returns resultant type and location
+         */
+        private CompValu GenerateFromRVal(TokenRVal rVal)
+        {
+            return GenerateFromRVal(rVal, null);
+        }
+        private CompValu GenerateFromRVal(TokenRVal rVal, TokenType[] argsig)
+        {
+            errorMessageToken = rVal;
+
+            /*
+             * Maybe the expression can be converted to a constant.
+             */
+            bool didOne;
+            do
+            {
+                didOne = false;
+                rVal = rVal.TryComputeConstant(LookupBodyConstants, ref didOne);
+            } while(didOne);
+
+            /*
+             * Generate code for the computation and return resulting type and location.
+             */
+            CompValu cVal = null;
+            if(rVal is TokenRValAsnPost)
+                cVal = GenerateFromRValAsnPost((TokenRValAsnPost)rVal);
+            if(rVal is TokenRValAsnPre)
+                cVal = GenerateFromRValAsnPre((TokenRValAsnPre)rVal);
+            if(rVal is TokenRValCall)
+                cVal = GenerateFromRValCall((TokenRValCall)rVal);
+            if(rVal is TokenRValCast)
+                cVal = GenerateFromRValCast((TokenRValCast)rVal);
+            if(rVal is TokenRValCondExpr)
+                cVal = GenerateFromRValCondExpr((TokenRValCondExpr)rVal);
+            if(rVal is TokenRValConst)
+                cVal = GenerateFromRValConst((TokenRValConst)rVal);
+            if(rVal is TokenRValInitDef)
+                cVal = GenerateFromRValInitDef((TokenRValInitDef)rVal);
+            if(rVal is TokenRValIsType)
+                cVal = GenerateFromRValIsType((TokenRValIsType)rVal);
+            if(rVal is TokenRValList)
+                cVal = GenerateFromRValList((TokenRValList)rVal);
+            if(rVal is TokenRValNewArIni)
+                cVal = GenerateFromRValNewArIni((TokenRValNewArIni)rVal);
+            if(rVal is TokenRValOpBin)
+                cVal = GenerateFromRValOpBin((TokenRValOpBin)rVal);
+            if(rVal is TokenRValOpUn)
+                cVal = GenerateFromRValOpUn((TokenRValOpUn)rVal);
+            if(rVal is TokenRValParen)
+                cVal = GenerateFromRValParen((TokenRValParen)rVal);
+            if(rVal is TokenRValRot)
+                cVal = GenerateFromRValRot((TokenRValRot)rVal);
+            if(rVal is TokenRValThis)
+                cVal = GenerateFromRValThis((TokenRValThis)rVal);
+            if(rVal is TokenRValUndef)
+                cVal = GenerateFromRValUndef((TokenRValUndef)rVal);
+            if(rVal is TokenRValVec)
+                cVal = GenerateFromRValVec((TokenRValVec)rVal);
+            if(rVal is TokenLVal)
+                cVal = GenerateFromLVal((TokenLVal)rVal, argsig);
+
+            if(cVal == null)
+                throw new Exception("bad rval class " + rVal.GetType().ToString());
+
+            /*
+             * Sanity check.
+             */
+            if(!youveAnError)
+            {
+                if(cVal.type == null)
+                    throw new Exception("cVal has no type " + cVal.GetType());
+                string cValType = cVal.type.ToString();
+                string rValType = rVal.GetRValType(this, argsig).ToString();
+                if(cValType == "bool")
+                    cValType = "integer";
+                if(rValType == "bool")
+                    rValType = "integer";
+                if(cValType != rValType)
+                {
+                    throw new Exception("cVal.type " + cValType + " != rVal.type " + rValType +
+                                         "  (" + rVal.GetType().Name + " " + rVal.SrcLoc + ")");
+                }
+            }
+
+            return cVal;
+        }
+
+        /**
+         * @brief compute the result of a binary operator (eg, add, subtract, multiply, lessthan)
+         * @param token = binary operator token, includes the left and right operands
+         * @returns where the resultant R-value is as something that doesn't have side effects
+         */
+        private CompValu GenerateFromRValOpBin(TokenRValOpBin token)
+        {
+            CompValu left, right;
+            string opcodeIndex = token.opcode.ToString();
+
+            /*
+             * Comma operators are special, as they say to compute the left-hand value and 
+             * discard it, then compute the right-hand argument and that is the result.
+             */
+            if(opcodeIndex == ",")
+            {
+
+                /*
+                 * Compute left-hand operand but throw away result.
+                 */
+                GenerateFromRVal(token.rValLeft);
+
+                /*
+                 * Compute right-hand operand and that is the value of the expression.
+                 */
+                return GenerateFromRVal(token.rValRight);
+            }
+
+            /*
+             * Simple overwriting assignments are their own special case,
+             * as we want to cast the R-value to the type of the L-value.
+             * And in the case of delegates, we want to use the arg signature
+             * of the delegate to select which overloaded method to use.
+             */
+            if(opcodeIndex == "=")
+            {
+                if(!(token.rValLeft is TokenLVal))
+                {
+                    ErrorMsg(token, "invalid L-value for =");
+                    return GenerateFromRVal(token.rValLeft);
+                }
+                left = GenerateFromLVal((TokenLVal)token.rValLeft);
+                right = Trivialize(GenerateFromRVal(token.rValRight, left.GetArgTypes()), token.rValRight);
+                left.PopPre(this, token.rValLeft);
+                right.PushVal(this, token.rValRight, left.type);  // push (left.type)right
+                left.PopPost(this, token.rValLeft);               // pop to left
+                return left;
+            }
+
+            /*
+             * There are String.Concat() methods available for 2, 3 and 4 operands.
+             * So see if we have a string concat op and optimize if so.
+             */
+            if((opcodeIndex == "+") ||
+                ((opcodeIndex == "+=") &&
+                 (token.rValLeft is TokenLVal) &&
+                 (token.rValLeft.GetRValType(this, null) is TokenTypeStr)))
+            {
+
+                /*
+                 * We are adding something.  Maybe it's a bunch of strings together.
+                 */
+                List<TokenRVal> scorvs = new List<TokenRVal>();
+                if(StringConcatOperands(token.rValLeft, token.rValRight, scorvs, token.opcode))
+                {
+
+                    /*
+                     * Evaluate all the operands, right-to-left on purpose per LSL scripting.
+                     */
+                    int i;
+                    int n = scorvs.Count;
+                    CompValu[] scocvs = new CompValu[n];
+                    for(i = n; --i >= 0;)
+                    {
+                        scocvs[i] = GenerateFromRVal(scorvs[i]);
+                        if(i > 0)
+                            scocvs[i] = Trivialize(scocvs[i], scorvs[i]);
+                    }
+
+                    /*
+                     * Figure out where to put the result.
+                     * A temp if '+', or back in original L-value if '+='.
+                     */
+                    CompValu retcv;
+                    if(opcodeIndex == "+")
+                    {
+                        retcv = new CompValuTemp(new TokenTypeStr(token.opcode), this);
+                    }
+                    else
+                    {
+                        retcv = GenerateFromLVal((TokenLVal)token.rValLeft);
+                    }
+                    retcv.PopPre(this, token);
+
+                    /*
+                     * Call the String.Concat() methods, passing operands in left-to-right order.
+                     * Force a cast to string (retcv.type) for each operand.
+                     */
+                    ++i;
+                    scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                    while(i + 3 < n)
+                    {
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ilGen.Emit(scorvs[i], OpCodes.Call, stringConcat4MethodInfo);
+                    }
+                    if(i + 2 < n)
+                    {
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ilGen.Emit(scorvs[i], OpCodes.Call, stringConcat3MethodInfo);
+                    }
+                    if(i + 1 < n)
+                    {
+                        ++i;
+                        scocvs[i].PushVal(this, scorvs[i], retcv.type);
+                        ilGen.Emit(scorvs[i], OpCodes.Call, stringConcat2MethodInfo);
+                    }
+
+                    /*
+                     * Put the result where we want it and return where we put it.
+                     */
+                    retcv.PopPost(this, token);
+                    return retcv;
+                }
+            }
+
+            /*
+             * If "&&&", it is a short-circuiting AND.
+             * Compute left-hand operand and if true, compute right-hand operand.
+             */
+            if(opcodeIndex == "&&&")
+            {
+                bool leftVal, rightVal;
+                left = GenerateFromRVal(token.rValLeft);
+                if(!IsConstBoolExpr(left, out leftVal))
+                {
+                    ScriptMyLabel falseLabel = ilGen.DefineLabel("ssandfalse");
+                    left.PushVal(this, tokenTypeBool);
+                    ilGen.Emit(token, OpCodes.Brfalse, falseLabel);
+                    right = GenerateFromRVal(token.rValRight);
+                    if(!IsConstBoolExpr(right, out rightVal))
+                    {
+                        right.PushVal(this, tokenTypeBool);
+                        goto donessand;
+                    }
+                    if(!rightVal)
+                    {
+                        ilGen.MarkLabel(falseLabel);
+                        return new CompValuInteger(new TokenTypeInt(token.rValLeft), 0);
+                    }
+                    ilGen.Emit(token, OpCodes.Ldc_I4_1);
+                    donessand:
+                    ScriptMyLabel doneLabel = ilGen.DefineLabel("ssanddone");
+                    ilGen.Emit(token, OpCodes.Br, doneLabel);
+                    ilGen.MarkLabel(falseLabel);
+                    ilGen.Emit(token, OpCodes.Ldc_I4_0);
+                    ilGen.MarkLabel(doneLabel);
+                    CompValuTemp retRVal = new CompValuTemp(new TokenTypeInt(token), this);
+                    retRVal.Pop(this, token);
+                    return retRVal;
+                }
+
+                if(!leftVal)
+                {
+                    return new CompValuInteger(new TokenTypeInt(token.rValLeft), 0);
+                }
+
+                right = GenerateFromRVal(token.rValRight);
+                if(!IsConstBoolExpr(right, out rightVal))
+                {
+                    right.PushVal(this, tokenTypeBool);
+                    CompValuTemp retRVal = new CompValuTemp(new TokenTypeInt(token), this);
+                    retRVal.Pop(this, token);
+                    return retRVal;
+                }
+                return new CompValuInteger(new TokenTypeInt(token), rightVal ? 1 : 0);
+            }
+
+            /*
+             * If "|||", it is a short-circuiting OR.
+             * Compute left-hand operand and if false, compute right-hand operand.
+             */
+            if(opcodeIndex == "|||")
+            {
+                bool leftVal, rightVal;
+                left = GenerateFromRVal(token.rValLeft);
+                if(!IsConstBoolExpr(left, out leftVal))
+                {
+                    ScriptMyLabel trueLabel = ilGen.DefineLabel("ssortrue");
+                    left.PushVal(this, tokenTypeBool);
+                    ilGen.Emit(token, OpCodes.Brtrue, trueLabel);
+                    right = GenerateFromRVal(token.rValRight);
+                    if(!IsConstBoolExpr(right, out rightVal))
+                    {
+                        right.PushVal(this, tokenTypeBool);
+                        goto donessor;
+                    }
+                    if(rightVal)
+                    {
+                        ilGen.MarkLabel(trueLabel);
+                        return new CompValuInteger(new TokenTypeInt(token.rValLeft), 1);
+                    }
+                    ilGen.Emit(token, OpCodes.Ldc_I4_0);
+                    donessor:
+                    ScriptMyLabel doneLabel = ilGen.DefineLabel("ssanddone");
+                    ilGen.Emit(token, OpCodes.Br, doneLabel);
+                    ilGen.MarkLabel(trueLabel);
+                    ilGen.Emit(token, OpCodes.Ldc_I4_1);
+                    ilGen.MarkLabel(doneLabel);
+                    CompValuTemp retRVal = new CompValuTemp(new TokenTypeInt(token), this);
+                    retRVal.Pop(this, token);
+                    return retRVal;
+                }
+
+                if(leftVal)
+                {
+                    return new CompValuInteger(new TokenTypeInt(token.rValLeft), 1);
+                }
+
+                right = GenerateFromRVal(token.rValRight);
+                if(!IsConstBoolExpr(right, out rightVal))
+                {
+                    right.PushVal(this, tokenTypeBool);
+                    CompValuTemp retRVal = new CompValuTemp(new TokenTypeInt(token), this);
+                    retRVal.Pop(this, token);
+                    return retRVal;
+                }
+                return new CompValuInteger(new TokenTypeInt(token), rightVal ? 1 : 0);
+            }
+
+            /*
+             * Computation of some sort, compute right-hand operand value then left-hand value
+             * because LSL is supposed to be right-to-left evaluation.
+             */
+            right = Trivialize(GenerateFromRVal(token.rValRight), token.rValRight);
+
+            /*
+             * If left is a script-defined class and there is a method with the operator's name,
+             * convert this to a call to that method with the right value as its single parameter.
+             * Except don't if the right value is 'undef' so they can always compare to undef.
+             */
+            TokenType leftType = token.rValLeft.GetRValType(this, null);
+            if((leftType is TokenTypeSDTypeClass) && !(right.type is TokenTypeUndef))
+            {
+                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)leftType;
+                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+                TokenType[] argsig = new TokenType[] { right.type };
+                TokenName funcName = new TokenName(token.opcode, "$op" + opcodeIndex);
+                TokenDeclVar declFunc = FindThisMember(sdtDecl, funcName, argsig);
+                if(declFunc != null)
+                {
+                    CheckAccess(declFunc, funcName);
+                    left = GenerateFromRVal(token.rValLeft);
+                    CompValu method = AccessInstanceMember(declFunc, left, token, false);
+                    CompValu[] argRVals = new CompValu[] { right };
+                    return GenerateACall(method, argRVals, token);
+                }
+            }
+
+            /*
+             * Formulate key string for binOpStrings = (lefttype)(operator)(righttype)
+             */
+            string leftIndex = leftType.ToString();
+            string rightIndex = right.type.ToString();
+            string key = leftIndex + opcodeIndex + rightIndex;
+
+            /*
+             * If that key exists in table, then the operation is defined between those types
+             * ... and it produces an R-value of type as given in the table.
+             */
+            BinOpStr binOpStr;
+            if(BinOpStr.defined.TryGetValue(key, out binOpStr))
+            {
+
+                /*
+                 * If table contained an explicit assignment type like +=, output the statement without
+                 * casting the L-value, then return the L-value as the resultant value.
+                 *
+                 * Make sure we don't include comparisons (such as ==, >=, etc).
+                 * Nothing like +=, -=, %=, etc, generate a boolean, only the comparisons.
+                 */
+                if((binOpStr.outtype != typeof(bool)) && opcodeIndex.EndsWith("=") && (opcodeIndex != "!="))
+                {
+                    if(!(token.rValLeft is TokenLVal))
+                    {
+                        ErrorMsg(token.rValLeft, "invalid L-value");
+                        return GenerateFromRVal(token.rValLeft);
+                    }
+                    left = GenerateFromLVal((TokenLVal)token.rValLeft);
+                    binOpStr.emitBO(this, token, left, right, left);
+                    return left;
+                }
+
+                /*
+                 * It's of the form left binop right.
+                 * Compute left, perform operation then put result in a temp.
+                 */
+                left = GenerateFromRVal(token.rValLeft);
+                CompValu retRVal = new CompValuTemp(TokenType.FromSysType(token.opcode, binOpStr.outtype), this);
+                binOpStr.emitBO(this, token, left, right, retRVal);
+                return retRVal;
+            }
+
+            /*
+             * Nothing in the table, check for comparing object pointers because of the myriad of types possible.
+             * This will compare list pointers, null pointers, script-defined type pointers, array pointers, etc.
+             * It will show equal iff the memory addresses are equal and that is good enough.
+             */
+            if(!leftType.ToSysType().IsValueType && !right.type.ToSysType().IsValueType && ((opcodeIndex == "==") || (opcodeIndex == "!=")))
+            {
+                CompValuTemp retRVal = new CompValuTemp(new TokenTypeInt(token), this);
+                left = GenerateFromRVal(token.rValLeft);
+                left.PushVal(this, token.rValLeft);
+                right.PushVal(this, token.rValRight);
+                ilGen.Emit(token, OpCodes.Ceq);
+                if(opcodeIndex == "!=")
+                {
+                    ilGen.Emit(token, OpCodes.Ldc_I4_1);
+                    ilGen.Emit(token, OpCodes.Xor);
+                }
+                retRVal.Pop(this, token);
+                return retRVal;
+            }
+
+            /*
+             * If the opcode ends with "=", it may be something like "+=".
+             * So look up the key as if we didn't have the "=" to tell us if the operation is legal.
+             * Also, the binary operation's output type must be the same as the L-value type.
+             * Likewise, integer += float not allowed because result is float, but float += integer is ok.
+             */
+            if(opcodeIndex.EndsWith("="))
+            {
+                key = leftIndex + opcodeIndex.Substring(0, opcodeIndex.Length - 1) + rightIndex;
+                if(BinOpStr.defined.TryGetValue(key, out binOpStr))
+                {
+                    if(!(token.rValLeft is TokenLVal))
+                    {
+                        ErrorMsg(token, "invalid L-value for <op>=");
+                        return GenerateFromRVal(token.rValLeft);
+                    }
+                    if(!binOpStr.rmwOK)
+                    {
+                        ErrorMsg(token, "<op>= not allowed: " + leftIndex + " " + opcodeIndex + " " + rightIndex);
+                        return new CompValuVoid(token);
+                    }
+
+                    /*
+                     * Now we know for something like %= that left%right is legal for the types given.
+                     */
+                    left = GenerateFromLVal((TokenLVal)token.rValLeft);
+                    if(binOpStr.outtype == leftType.ToSysType())
+                    {
+                        binOpStr.emitBO(this, token, left, right, left);
+                    }
+                    else
+                    {
+                        CompValu temp = new CompValuTemp(TokenType.FromSysType(token, binOpStr.outtype), this);
+                        binOpStr.emitBO(this, token, left, right, temp);
+                        left.PopPre(this, token);
+                        temp.PushVal(this, token, leftType);
+                        left.PopPost(this, token);
+                    }
+                    return left;
+                }
+            }
+
+            /*
+             * Can't find it, oh well.
+             */
+            ErrorMsg(token, "op not defined: " + leftIndex + " " + opcodeIndex + " " + rightIndex);
+            return new CompValuVoid(token);
+        }
+
+        /**
+         * @brief Queue the given operands to the end of the scos list.
+         *        If it can be broken down into more string concat operands, do so.
+         *        Otherwise, just push it as one operand.
+         * @param leftRVal  = left-hand operand of a '+' operation
+         * @param rightRVal = right-hand operand of a '+' operation
+         * @param scos      = left-to-right list of operands for the string concat so far
+         * @param addop     = the add operator token (either '+' or '+=')
+         * @returns false: neither operand is a string, nothing added to scos
+         *           true: scos = updated with leftRVal then rightRVal added onto the end, possibly broken down further
+         */
+        private bool StringConcatOperands(TokenRVal leftRVal, TokenRVal rightRVal, List<TokenRVal> scos, TokenKw addop)
+        {
+            /*
+             * If neither operand is a string (eg, float+integer), then the result isn't going to be a string.
+             */
+            TokenType leftType = leftRVal.GetRValType(this, null);
+            TokenType rightType = rightRVal.GetRValType(this, null);
+            if(!(leftType is TokenTypeStr) && !(rightType is TokenTypeStr))
+                return false;
+
+            /*
+             * Also, list+string => list so reject that too.
+             * Also, string+list => list so reject that too.
+             */
+            if(leftType is TokenTypeList)
+                return false;
+            if(rightType is TokenTypeList)
+                return false;
+
+            /*
+             * Append values to the end of the list in left-to-right order.
+             * If value is formed from a something+something => string, 
+             * push them as separate values, otherwise push as one value.
+             */
+            StringConcatOperand(leftType, leftRVal, scos);
+            StringConcatOperand(rightType, rightRVal, scos);
+
+            /*
+             * Maybe constant strings can be concatted.
+             */
+            try
+            {
+                int len;
+                while(((len = scos.Count) >= 2) &&
+                       ((leftRVal = scos[len - 2]) is TokenRValConst) &&
+                       ((rightRVal = scos[len - 1]) is TokenRValConst))
+                {
+                    object sum = addop.binOpConst(((TokenRValConst)leftRVal).val,
+                                                   ((TokenRValConst)rightRVal).val);
+                    scos[len - 2] = new TokenRValConst(addop, sum);
+                    scos.RemoveAt(len - 1);
+                }
+            }
+            catch
+            {
+            }
+
+            /*
+             * We pushed some string stuff.
+             */
+            return true;
+        }
+
+        /**
+         * @brief Queue the given operand to the end of the scos list.
+         *        If it can be broken down into more string concat operands, do so.
+         *        Otherwise, just push it as one operand.
+         * @param type = rVal's resultant type
+         * @param rVal = operand to examine
+         * @param scos = left-to-right list of operands for the string concat so far
+         * @returns with scos = updated with rVal added onto the end, possibly broken down further
+         */
+        private void StringConcatOperand(TokenType type, TokenRVal rVal, List<TokenRVal> scos)
+        {
+            bool didOne;
+            do
+            {
+                didOne = false;
+                rVal = rVal.TryComputeConstant(LookupBodyConstants, ref didOne);
+            } while(didOne);
+
+            if(!(type is TokenTypeStr))
+                goto pushasis;
+            if(!(rVal is TokenRValOpBin))
+                goto pushasis;
+            TokenRValOpBin rValOpBin = (TokenRValOpBin)rVal;
+            if(!(rValOpBin.opcode is TokenKwAdd))
+                goto pushasis;
+            if(StringConcatOperands(rValOpBin.rValLeft, rValOpBin.rValRight, scos, rValOpBin.opcode))
+                return;
+            pushasis:
+            scos.Add(rVal);
+        }
+
+        /**
+         * @brief compute the result of an unary operator
+         * @param token = unary operator token, includes the operand
+         * @returns where the resultant R-value is
+         */
+        private CompValu GenerateFromRValOpUn(TokenRValOpUn token)
+        {
+            CompValu inRVal = GenerateFromRVal(token.rVal);
+
+            /*
+             * Script-defined types can define their own methods to handle unary operators.
+             */
+            if(inRVal.type is TokenTypeSDTypeClass)
+            {
+                TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)inRVal.type;
+                TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+                TokenName funcName = new TokenName(token.opcode, "$op" + token.opcode.ToString());
+                TokenDeclVar declFunc = FindThisMember(sdtDecl, funcName, zeroArgs);
+                if(declFunc != null)
+                {
+                    CheckAccess(declFunc, funcName);
+                    CompValu method = AccessInstanceMember(declFunc, inRVal, token, false);
+                    return GenerateACall(method, zeroCompValus, token);
+                }
+            }
+
+            /*
+             * Otherwise use the default.
+             */
+            return UnOpGenerate(inRVal, token.opcode);
+        }
+
+        /**
+         * @brief postfix operator -- this returns the type and location of the resultant value
+         */
+        private CompValu GenerateFromRValAsnPost(TokenRValAsnPost asnPost)
+        {
+            CompValu lVal = GenerateFromLVal(asnPost.lVal);
+
+            /*
+             * Make up a temp to save original value in.
+             */
+            CompValuTemp result = new CompValuTemp(lVal.type, this);
+
+            /*
+             * Prepare to pop incremented value back into variable being incremented.
+             */
+            lVal.PopPre(this, asnPost.lVal);
+
+            /*
+             * Copy original value to temp and leave value on stack.
+             */
+            lVal.PushVal(this, asnPost.lVal);
+            ilGen.Emit(asnPost.lVal, OpCodes.Dup);
+            result.Pop(this, asnPost.lVal);
+
+            /*
+             * Perform the ++/--.
+             */
+            if((lVal.type is TokenTypeChar) || (lVal.type is TokenTypeInt))
+            {
+                ilGen.Emit(asnPost, OpCodes.Ldc_I4_1);
+            }
+            else if(lVal.type is TokenTypeFloat)
+            {
+                ilGen.Emit(asnPost, OpCodes.Ldc_R4, 1.0f);
+            }
+            else
+            {
+                lVal.PopPost(this, asnPost.lVal);
+                ErrorMsg(asnPost, "invalid type for " + asnPost.postfix.ToString());
+                return lVal;
+            }
+            switch(asnPost.postfix.ToString())
+            {
+                case "++":
+                    {
+                        ilGen.Emit(asnPost, OpCodes.Add);
+                        break;
+                    }
+                case "--":
+                    {
+                        ilGen.Emit(asnPost, OpCodes.Sub);
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown asnPost op");
+            }
+
+            /*
+             * Store new value in original variable.
+             */
+            lVal.PopPost(this, asnPost.lVal);
+
+            return result;
+        }
+
+        /**
+         * @brief prefix operator -- this returns the type and location of the resultant value
+         */
+        private CompValu GenerateFromRValAsnPre(TokenRValAsnPre asnPre)
+        {
+            CompValu lVal = GenerateFromLVal(asnPre.lVal);
+
+            /*
+             * Make up a temp to put result in.
+             */
+            CompValuTemp result = new CompValuTemp(lVal.type, this);
+
+            /*
+             * Prepare to pop incremented value back into variable being incremented.
+             */
+            lVal.PopPre(this, asnPre.lVal);
+
+            /*
+             * Push original value.
+             */
+            lVal.PushVal(this, asnPre.lVal);
+
+            /*
+             * Perform the ++/--.
+             */
+            if((lVal.type is TokenTypeChar) || (lVal.type is TokenTypeInt))
+            {
+                ilGen.Emit(asnPre, OpCodes.Ldc_I4_1);
+            }
+            else if(lVal.type is TokenTypeFloat)
+            {
+                ilGen.Emit(asnPre, OpCodes.Ldc_R4, 1.0f);
+            }
+            else
+            {
+                lVal.PopPost(this, asnPre.lVal);
+                ErrorMsg(asnPre, "invalid type for " + asnPre.prefix.ToString());
+                return lVal;
+            }
+            switch(asnPre.prefix.ToString())
+            {
+                case "++":
+                    {
+                        ilGen.Emit(asnPre, OpCodes.Add);
+                        break;
+                    }
+                case "--":
+                    {
+                        ilGen.Emit(asnPre, OpCodes.Sub);
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown asnPre op");
+            }
+
+            /*
+             * Store new value in temp variable, keeping new value on stack.
+             */
+            ilGen.Emit(asnPre.lVal, OpCodes.Dup);
+            result.Pop(this, asnPre.lVal);
+
+            /*
+             * Store new value in original variable.
+             */
+            lVal.PopPost(this, asnPre.lVal);
+
+            return result;
+        }
+
+        /**
+         * @brief Generate code that calls a function or object's method.
+         * @returns where the call's return value is stored (a TokenTypeVoid if void)
+         */
+        private CompValu GenerateFromRValCall(TokenRValCall call)
+        {
+            CompValu method;
+            CompValu[] argRVals;
+            int i, nargs;
+            TokenRVal arg;
+            TokenType[] argTypes;
+
+            /*
+             * Compute the values of all the function's call arguments.
+             * Save where the computation results are in the argRVals[] array.
+             * Might as well build the argument signature from the argument types, too.
+             */
+            nargs = call.nArgs;
+            argRVals = new CompValu[nargs];
+            argTypes = new TokenType[nargs];
+            if(nargs > 0)
+            {
+                i = 0;
+                for(arg = call.args; arg != null; arg = (TokenRVal)arg.nextToken)
+                {
+                    argRVals[i] = GenerateFromRVal(arg);
+                    argTypes[i] = argRVals[i].type;
+                    i++;
+                }
+            }
+
+            /*
+             * Get function/method's entrypoint that matches the call argument types.
+             */
+            method = GenerateFromRVal(call.meth, argTypes);
+            if(method == null)
+                return null;
+
+            return GenerateACall(method, argRVals, call);
+        }
+
+        /**
+         * @brief Generate call to a function/method.
+         * @param method = function/method being called
+         * @param argVRVals = its call parameters (zero length if none)
+         * @param call = where in source code call is being made from (for error messages)
+         * @returns type and location of return value (CompValuVoid if none)
+         */
+        private CompValu GenerateACall(CompValu method, CompValu[] argRVals, Token call)
+        {
+            CompValuTemp result;
+            int i, nArgs;
+            TokenType retType;
+            TokenType[] argTypes;
+
+            /*
+             * Must be some kind of callable.
+             */
+            retType = method.GetRetType();  // TokenTypeVoid if void; null means a variable
+            if(retType == null)
+            {
+                ErrorMsg(call, "must be a delegate, function or method");
+                return new CompValuVoid(call);
+            }
+
+            /*
+             * Get a location for return value.
+             */
+            if(retType is TokenTypeVoid)
+            {
+                result = new CompValuVoid(call);
+            }
+            else
+            {
+                result = new CompValuTemp(retType, this);
+            }
+
+            /*
+             * Make sure all arguments are trivial, ie, don't involve their own call labels.
+             * For any that aren't, output code to calculate the arg and put in a temporary.
+             */
+            nArgs = argRVals.Length;
+            for(i = 0; i < nArgs; i++)
+            {
+                if(!argRVals[i].IsReadTrivial(this, call))
+                {
+                    argRVals[i] = Trivialize(argRVals[i], call);
+                }
+            }
+
+            /*
+             * Inline functions know how to generate their own call.
+             */
+            if(method is CompValuInline)
+            {
+                CompValuInline inline = (CompValuInline)method;
+                inline.declInline.CodeGen(this, call, result, argRVals);
+                return result;
+            }
+
+            /*
+             * Push whatever the function/method needs as a this argument, if anything.
+             */
+            method.CallPre(this, call);
+
+            /*
+             * Push the script-visible args, left-to-right.
+             */
+            argTypes = method.GetArgTypes();
+            for(i = 0; i < nArgs; i++)
+            {
+                if(argTypes == null)
+                {
+                    argRVals[i].PushVal(this, call);
+                }
+                else
+                {
+                    argRVals[i].PushVal(this, call, argTypes[i]);
+                }
+            }
+
+            /*
+             * Now output call instruction.
+             */
+            method.CallPost(this, call);
+
+            /*
+             * Deal with the return value (if any), by putting it in 'result'.
+             */
+            result.Pop(this, call, retType);
+            return result;
+        }
+
+        /**
+         * @brief This is needed to avoid nesting call labels around non-trivial properties.
+         *        It should be used for the second (and later) operands.
+         *        Note that a 'call' is considered an operator, so all arguments of a call
+         *        should be trivialized, but the method itself does not need to be.
+         */
+        public CompValu Trivialize(CompValu operand, Token errorAt)
+        {
+            if(operand.IsReadTrivial(this, errorAt))
+                return operand;
+            CompValuTemp temp = new CompValuTemp(operand.type, this);
+            operand.PushVal(this, errorAt);
+            temp.Pop(this, errorAt);
+            return temp;
+        }
+
+        /**
+         * @brief Generate code that casts a value to a particular type.
+         * @returns where the result of the conversion is stored.
+         */
+        private CompValu GenerateFromRValCast(TokenRValCast cast)
+        {
+            /*
+             * If casting to a delegate type, use the argment signature 
+             * of the delegate to help select the function/method, eg, 
+             *    '(delegate string(integer))ToString'
+             * will select 'string ToString(integer x)'
+             * instaead of 'string ToString(float x)' or anything else
+             */
+            TokenType[] argsig = null;
+            TokenType outType = cast.castTo;
+            if(outType is TokenTypeSDTypeDelegate)
+            {
+                argsig = ((TokenTypeSDTypeDelegate)outType).decl.GetArgTypes();
+            }
+
+            /*
+             * Generate the value that is being cast.
+             * If the value is already the requested type, just use it as is.
+             */
+            CompValu inRVal = GenerateFromRVal(cast.rVal, argsig);
+            if(inRVal.type == outType)
+                return inRVal;
+
+            /*
+             * Different type, generate casting code, putting the result in a temp of the output type.
+             */
+            CompValu outRVal = new CompValuTemp(outType, this);
+            outRVal.PopPre(this, cast);
+            inRVal.PushVal(this, cast, outType, true);
+            outRVal.PopPost(this, cast);
+            return outRVal;
+        }
+
+        /**
+         * @brief Compute conditional expression value.
+         * @returns type and location of computed value.
+         */
+        private CompValu GenerateFromRValCondExpr(TokenRValCondExpr rValCondExpr)
+        {
+            bool condVal;
+            CompValu condValu = GenerateFromRVal(rValCondExpr.condExpr);
+            if(IsConstBoolExpr(condValu, out condVal))
+            {
+                return GenerateFromRVal(condVal ? rValCondExpr.trueExpr : rValCondExpr.falseExpr);
+            }
+
+            ScriptMyLabel falseLabel = ilGen.DefineLabel("condexfalse");
+            ScriptMyLabel doneLabel = ilGen.DefineLabel("condexdone");
+
+            condValu.PushVal(this, rValCondExpr.condExpr, tokenTypeBool);
+            ilGen.Emit(rValCondExpr, OpCodes.Brfalse, falseLabel);
+
+            CompValu trueValu = GenerateFromRVal(rValCondExpr.trueExpr);
+            trueValu.PushVal(this, rValCondExpr.trueExpr);
+            ilGen.Emit(rValCondExpr, OpCodes.Br, doneLabel);
+
+            ilGen.MarkLabel(falseLabel);
+            CompValu falseValu = GenerateFromRVal(rValCondExpr.falseExpr);
+            falseValu.PushVal(this, rValCondExpr.falseExpr);
+
+            if(trueValu.type.GetType() != falseValu.type.GetType())
+            {
+                ErrorMsg(rValCondExpr, "? operands " + trueValu.type.ToString() + " : " +
+                              falseValu.type.ToString() + " must be of same type");
+            }
+
+            ilGen.MarkLabel(doneLabel);
+            CompValuTemp retRVal = new CompValuTemp(trueValu.type, this);
+            retRVal.Pop(this, rValCondExpr);
+            return retRVal;
+        }
+
+        /**
+         * @brief Constant in the script somewhere
+         * @returns where the constants value is stored
+         */
+        private CompValu GenerateFromRValConst(TokenRValConst rValConst)
+        {
+            switch(rValConst.type)
+            {
+                case TokenRValConstType.CHAR:
+                    {
+                        return new CompValuChar(new TokenTypeChar(rValConst), (char)(rValConst.val));
+                    }
+                case TokenRValConstType.FLOAT:
+                    {
+                        return new CompValuFloat(new TokenTypeFloat(rValConst), (double)(rValConst.val));
+                    }
+                case TokenRValConstType.INT:
+                    {
+                        return new CompValuInteger(new TokenTypeInt(rValConst), (int)(rValConst.val));
+                    }
+                case TokenRValConstType.KEY:
+                    {
+                        return new CompValuString(new TokenTypeKey(rValConst), (string)(rValConst.val));
+                    }
+                case TokenRValConstType.STRING:
+                    {
+                        return new CompValuString(new TokenTypeStr(rValConst), (string)(rValConst.val));
+                    }
+            }
+            throw new Exception("unknown constant type " + rValConst.val.GetType());
+        }
+
+        /**
+         * @brief generate a new list object
+         * @param rValList = an rVal to create it from
+         */
+        private CompValu GenerateFromRValList(TokenRValList rValList)
+        {
+            /*
+             * Compute all element values and remember where we put them.
+             * Do it right-to-left as customary for LSL scripts.
+             */
+            int i = 0;
+            TokenRVal lastRVal = null;
+            for(TokenRVal val = rValList.rVal; val != null; val = (TokenRVal)val.nextToken)
+            {
+                i++;
+                val.prevToken = lastRVal;
+                lastRVal = val;
+            }
+            CompValu[] vals = new CompValu[i];
+            for(TokenRVal val = lastRVal; val != null; val = (TokenRVal)val.prevToken)
+            {
+                vals[--i] = GenerateFromRVal(val);
+            }
+
+            /*
+             * This is the temp that will hold the created list.
+             */
+            CompValuTemp newList = new CompValuTemp(new TokenTypeList(rValList.rVal), this);
+
+            /*
+             * Create a temp object[] array to hold all the initial values.
+             */
+            ilGen.Emit(rValList, OpCodes.Ldc_I4, rValList.nItems);
+            ilGen.Emit(rValList, OpCodes.Newarr, typeof(object));
+
+            /*
+             * Populate the array.
+             */
+            i = 0;
+            for(TokenRVal val = rValList.rVal; val != null; val = (TokenRVal)val.nextToken)
+            {
+
+                /*
+                 * Get pointer to temp array object.
+                 */
+                ilGen.Emit(rValList, OpCodes.Dup);
+
+                /*
+                 * Get index in that array.
+                 */
+                ilGen.Emit(rValList, OpCodes.Ldc_I4, i);
+
+                /*
+                 * Store initialization value in array location.
+                 * However, floats and ints need to be converted to LSL_Float and LSL_Integer,
+                 * or things like llSetPayPrice() will puque when they try to cast the elements
+                 * to LSL_Float or LSL_Integer.  Likewise with string/LSL_String.
+                 *
+                 * Maybe it's already LSL-boxed so we don't do anything with it except make sure
+                 * it is an object, not a struct.
+                 */
+                CompValu eRVal = vals[i++];
+                eRVal.PushVal(this, val);
+                if(eRVal.type.ToLSLWrapType() == null)
+                {
+                    if(eRVal.type is TokenTypeFloat)
+                    {
+                        ilGen.Emit(val, OpCodes.Newobj, lslFloatConstructorInfo);
+                        ilGen.Emit(val, OpCodes.Box, typeof(LSL_Float));
+                    }
+                    else if(eRVal.type is TokenTypeInt)
+                    {
+                        ilGen.Emit(val, OpCodes.Newobj, lslIntegerConstructorInfo);
+                        ilGen.Emit(val, OpCodes.Box, typeof(LSL_Integer));
+                    }
+                    else if((eRVal.type is TokenTypeKey) || (eRVal.type is TokenTypeStr))
+                    {
+                        ilGen.Emit(val, OpCodes.Newobj, lslStringConstructorInfo);
+                        ilGen.Emit(val, OpCodes.Box, typeof(LSL_String));
+                    }
+                    else if(eRVal.type.ToSysType().IsValueType)
+                    {
+                        ilGen.Emit(val, OpCodes.Box, eRVal.type.ToSysType());
+                    }
+                }
+                else if(eRVal.type.ToLSLWrapType().IsValueType)
+                {
+
+                    // Convert the LSL value structs to an object of the LSL-boxed type
+                    ilGen.Emit(val, OpCodes.Box, eRVal.type.ToLSLWrapType());
+                }
+                ilGen.Emit(val, OpCodes.Stelem, typeof(object));
+            }
+
+            /*
+             * Create new list object from temp initial value array (whose ref is still on the stack).
+             */
+            ilGen.Emit(rValList, OpCodes.Newobj, lslListConstructorInfo);
+            newList.Pop(this, rValList);
+            return newList;
+        }
+
+        /**
+         * @brief New array allocation with initializer expressions.
+         */
+        private CompValu GenerateFromRValNewArIni(TokenRValNewArIni rValNewArIni)
+        {
+            return MallocAndInitArray(rValNewArIni.arrayType, rValNewArIni.valueList);
+        }
+
+        /**
+         * @brief Mallocate and initialize an array from its initialization list.
+         * @param arrayType = type of the array to be allocated and initialized
+         * @param values    = initialization value list used to size and initialize the array.
+         * @returns memory location of the resultant initialized array.
+         */
+        private CompValu MallocAndInitArray(TokenType arrayType, TokenList values)
+        {
+            TokenDeclSDTypeClass arrayDecl = ((TokenTypeSDTypeClass)arrayType).decl;
+            TokenType eleType = arrayDecl.arrayOfType;
+            int rank = arrayDecl.arrayOfRank;
+
+            // Get size of each of the dimensions by scanning the initialization value list
+            int[] dimSizes = new int[rank];
+            FillInDimSizes(dimSizes, 0, rank, values);
+
+            // Figure out where the array's $new() method is
+            TokenType[] newargsig = new TokenType[rank];
+            for(int k = 0; k < rank; k++)
+            {
+                newargsig[k] = tokenTypeInt;
+            }
+            TokenDeclVar newMeth = FindThisMember(arrayDecl, new TokenName(null, "$new"), newargsig);
+
+            // Output a call to malloc the array with all default values
+            //    array = ArrayType.$new (dimSizes[0], dimSizes[1], ...)
+            CompValuTemp array = new CompValuTemp(arrayType, this);
+            PushXMRInst();
+            for(int k = 0; k < rank; k++)
+            {
+                ilGen.Emit(values, OpCodes.Ldc_I4, dimSizes[k]);
+            }
+            ilGen.Emit(values, OpCodes.Call, newMeth.ilGen);
+            array.Pop(this, arrayType);
+
+            // Figure out where the array's Set() method is
+            TokenType[] setargsig = new TokenType[rank + 1];
+            for(int k = 0; k < rank; k++)
+            {
+                setargsig[k] = tokenTypeInt;
+            }
+            setargsig[rank] = eleType;
+            TokenDeclVar setMeth = FindThisMember(arrayDecl, new TokenName(null, "Set"), setargsig);
+
+            // Fill in the array with the initializer values
+            FillInInitVals(array, setMeth, dimSizes, 0, rank, values, eleType);
+
+            // The array is our resultant value
+            return array;
+        }
+
+        /**
+         * @brief Compute an array's dimensions given its initialization value list
+         * @param dimSizes = filled in with array's dimensions
+         * @param dimNo    = what dimension the 'values' list applies to
+         * @param rank     = total number of dimensions of the array
+         * @param values   = list of values to initialize the array's 'dimNo' dimension with
+         * @returns with dimSizes[dimNo..rank-1] filled in
+         */
+        private static void FillInDimSizes(int[] dimSizes, int dimNo, int rank, TokenList values)
+        {
+            // the size of a dimension is the largest number of initializer elements at this level
+            // for dimNo 0, this is the number of elements in the top-level list
+            if(dimSizes[dimNo] < values.tl.Count)
+                dimSizes[dimNo] = values.tl.Count;
+
+            // see if there is another dimension to calculate
+            if(++dimNo < rank)
+            {
+
+                // its size is the size of the largest initializer list at the next inner level
+                foreach(Token val in values.tl)
+                {
+                    if(val is TokenList)
+                    {
+                        TokenList subvals = (TokenList)val;
+                        FillInDimSizes(dimSizes, dimNo, rank, subvals);
+                    }
+                }
+            }
+        }
+
+        /**
+         * @brief Output code to fill in array's initialization values
+         * @param array      = array to be filled in
+         * @param setMeth    = the array's Set() method
+         * @param subscripts = holds subscripts being built
+         * @param dimNo      = which dimension the 'values' are for
+         * @param values     = list of initialization values for dimension 'dimNo'
+         * @param rank       = number of dimensions of 'array'
+         * @param values     = list of values to initialize the array's 'dimNo' dimension with
+         * @param eleType    = the element's type
+         * @returns with code emitted to initialize array's [subscripts[0], ..., subscripts[dimNo-1], *, *, ...]
+         *                                                          dimNo and up completely filled ---^
+         */
+        private void FillInInitVals(CompValu array, TokenDeclVar setMeth, int[] subscripts, int dimNo, int rank, TokenList values, TokenType eleType)
+        {
+            subscripts[dimNo] = 0;
+            foreach(Token val in values.tl)
+            {
+                CompValu initValue = null;
+
+                /*
+                 * If it is a sublist, process it.
+                 *    If we don't have enough subscripts yet, hopefully that sublist will have enough.
+                 *    If we already have enough subscripts, then that sublist can be for an element of this supposedly jagged array.
+                 */
+                if(val is TokenList)
+                {
+                    TokenList sublist = (TokenList)val;
+                    if(dimNo + 1 < rank)
+                    {
+
+                        /*
+                         * We don't have enough subscripts yet, hopefully the sublist has the rest.
+                         */
+                        FillInInitVals(array, setMeth, subscripts, dimNo + 1, rank, sublist, eleType);
+                    }
+                    else if((eleType is TokenTypeSDTypeClass) && (((TokenTypeSDTypeClass)eleType).decl.arrayOfType == null))
+                    {
+
+                        /*
+                         * If we aren't a jagged array either, we can't do anything with the sublist.
+                         */
+                        ErrorMsg(val, "too many brace levels");
+                    }
+                    else
+                    {
+
+                        /*
+                         * We are a jagged array, so malloc a subarray and initialize it with the sublist.
+                         * Then we can use that subarray to fill this array's element.
+                         */
+                        initValue = MallocAndInitArray(eleType, sublist);
+                    }
+                }
+
+                /*
+                 * If it is a value expression, then output code to compute the value.
+                 */
+                if(val is TokenRVal)
+                {
+                    if(dimNo + 1 < rank)
+                    {
+                        ErrorMsg((Token)val, "not enough brace levels");
+                    }
+                    else
+                    {
+                        initValue = GenerateFromRVal((TokenRVal)val);
+                    }
+                }
+
+                /*
+                 * If there is an initValue, output "array.Set (subscript[0], subscript[1], ..., initValue)"
+                 */
+                if(initValue != null)
+                {
+                    array.PushVal(this, val);
+                    for(int i = 0; i <= dimNo; i++)
+                    {
+                        ilGen.Emit(val, OpCodes.Ldc_I4, subscripts[i]);
+                    }
+                    initValue.PushVal(this, val, eleType);
+                    ilGen.Emit(val, OpCodes.Call, setMeth.ilGen);
+                }
+
+                /*
+                 * That subscript is processed one way or another, on to the next.
+                 */
+                subscripts[dimNo]++;
+            }
+        }
+
+        /**
+         * @brief parenthesized expression
+         * @returns type and location of the result of the computation.
+         */
+        private CompValu GenerateFromRValParen(TokenRValParen rValParen)
+        {
+            return GenerateFromRVal(rValParen.rVal);
+        }
+
+        /**
+         * @brief create a rotation object from the x,y,z,w value expressions.
+         */
+        private CompValu GenerateFromRValRot(TokenRValRot rValRot)
+        {
+            CompValu xRVal, yRVal, zRVal, wRVal;
+
+            xRVal = Trivialize(GenerateFromRVal(rValRot.xRVal), rValRot);
+            yRVal = Trivialize(GenerateFromRVal(rValRot.yRVal), rValRot);
+            zRVal = Trivialize(GenerateFromRVal(rValRot.zRVal), rValRot);
+            wRVal = Trivialize(GenerateFromRVal(rValRot.wRVal), rValRot);
+            return new CompValuRot(new TokenTypeRot(rValRot), xRVal, yRVal, zRVal, wRVal);
+        }
+
+        /**
+         * @brief Using 'this' as a pointer to the current script-defined instance object.
+         *        The value is located in arg #0 of the current instance method.
+         */
+        private CompValu GenerateFromRValThis(TokenRValThis zhis)
+        {
+            if(!IsSDTInstMethod())
+            {
+                ErrorMsg(zhis, "cannot access instance member of class from static method");
+                return new CompValuVoid(zhis);
+            }
+            return new CompValuArg(curDeclFunc.sdtClass.MakeRefToken(zhis), 0);
+        }
+
+        /**
+         * @brief 'undefined' constant.
+         *        If this constant gets written to an array element, it will delete that element from the array.
+         *        If the script retrieves an element by key that is not defined, it will get this value.
+         *        This value can be stored in and retrieved from variables of type 'object' or script-defined classes.
+         *        It is a runtime error to cast this value to any other type, eg, 
+         *        we don't allow list or string variables to be null pointers.
+         */
+        private CompValu GenerateFromRValUndef(TokenRValUndef rValUndef)
+        {
+            return new CompValuNull(new TokenTypeUndef(rValUndef));
+        }
+
+        /**
+         * @brief create a vector object from the x,y,z value expressions.
+         */
+        private CompValu GenerateFromRValVec(TokenRValVec rValVec)
+        {
+            CompValu xRVal, yRVal, zRVal;
+
+            xRVal = Trivialize(GenerateFromRVal(rValVec.xRVal), rValVec);
+            yRVal = Trivialize(GenerateFromRVal(rValVec.yRVal), rValVec);
+            zRVal = Trivialize(GenerateFromRVal(rValVec.zRVal), rValVec);
+            return new CompValuVec(new TokenTypeVec(rValVec), xRVal, yRVal, zRVal);
+        }
+
+        /**
+         * @brief Generate code to get the default initialization value for a variable.
+         */
+        private CompValu GenerateFromRValInitDef(TokenRValInitDef rValInitDef)
+        {
+            TokenType type = rValInitDef.type;
+
+            if(type is TokenTypeChar)
+            {
+                return new CompValuChar(type, (char)0);
+            }
+            if(type is TokenTypeRot)
+            {
+                CompValuFloat x = new CompValuFloat(type, ScriptBaseClass.ZERO_ROTATION.x);
+                CompValuFloat y = new CompValuFloat(type, ScriptBaseClass.ZERO_ROTATION.y);
+                CompValuFloat z = new CompValuFloat(type, ScriptBaseClass.ZERO_ROTATION.z);
+                CompValuFloat s = new CompValuFloat(type, ScriptBaseClass.ZERO_ROTATION.s);
+                return new CompValuRot(type, x, y, z, s);
+            }
+            if((type is TokenTypeKey) || (type is TokenTypeStr))
+            {
+                return new CompValuString(type, "");
+            }
+            if(type is TokenTypeVec)
+            {
+                CompValuFloat x = new CompValuFloat(type, ScriptBaseClass.ZERO_VECTOR.x);
+                CompValuFloat y = new CompValuFloat(type, ScriptBaseClass.ZERO_VECTOR.y);
+                CompValuFloat z = new CompValuFloat(type, ScriptBaseClass.ZERO_VECTOR.z);
+                return new CompValuVec(type, x, y, z);
+            }
+            if(type is TokenTypeInt)
+            {
+                return new CompValuInteger(type, 0);
+            }
+            if(type is TokenTypeFloat)
+            {
+                return new CompValuFloat(type, 0);
+            }
+            if(type is TokenTypeVoid)
+            {
+                return new CompValuVoid(type);
+            }
+
+            /*
+             * Default for 'object' type is 'undef'.
+             * Likewise for script-defined classes and interfaces.
+             */
+            if((type is TokenTypeObject) || (type is TokenTypeSDTypeClass) || (type is TokenTypeSDTypeDelegate) ||
+                (type is TokenTypeSDTypeInterface) || (type is TokenTypeExc))
+            {
+                return new CompValuNull(type);
+            }
+
+            /*
+             * array and list
+             */
+            CompValuTemp temp = new CompValuTemp(type, this);
+            PushDefaultValue(type);
+            temp.Pop(this, rValInitDef, type);
+            return temp;
+        }
+
+        /**
+         * @brief Generate code to process an <rVal> is <type> expression, and produce a boolean value.
+         */
+        private CompValu GenerateFromRValIsType(TokenRValIsType rValIsType)
+        {
+            /*
+             * Expression we want to know the type of.
+             */
+            CompValu val = GenerateFromRVal(rValIsType.rValExp);
+
+            /*
+             * Pass it in to top-level type expression decoder.
+             */
+            return GenerateFromTypeExp(val, rValIsType.typeExp);
+        }
+
+        /**
+         * @brief See if the type of the given value matches the type expression.
+         * @param val = where the value to be evaluated is stored
+         * @param typeExp = script tokens representing type expression
+         * @returns location where the boolean result is stored
+         */
+        private CompValu GenerateFromTypeExp(CompValu val, TokenTypeExp typeExp)
+        {
+            if(typeExp is TokenTypeExpBinOp)
+            {
+                CompValu left = GenerateFromTypeExp(val, ((TokenTypeExpBinOp)typeExp).leftOp);
+                CompValu right = GenerateFromTypeExp(val, ((TokenTypeExpBinOp)typeExp).rightOp);
+                CompValuTemp result = new CompValuTemp(tokenTypeBool, this);
+                Token op = ((TokenTypeExpBinOp)typeExp).binOp;
+                left.PushVal(this, ((TokenTypeExpBinOp)typeExp).leftOp);
+                right.PushVal(this, ((TokenTypeExpBinOp)typeExp).rightOp);
+                if(op is TokenKwAnd)
+                {
+                    ilGen.Emit(typeExp, OpCodes.And);
+                }
+                else if(op is TokenKwOr)
+                {
+                    ilGen.Emit(typeExp, OpCodes.Or);
+                }
+                else
+                {
+                    throw new Exception("unknown TokenTypeExpBinOp " + op.GetType());
+                }
+                result.Pop(this, typeExp);
+                return result;
+            }
+            if(typeExp is TokenTypeExpNot)
+            {
+                CompValu interm = GenerateFromTypeExp(val, ((TokenTypeExpNot)typeExp).typeExp);
+                CompValuTemp result = new CompValuTemp(tokenTypeBool, this);
+                interm.PushVal(this, ((TokenTypeExpNot)typeExp).typeExp, tokenTypeBool);
+                ilGen.Emit(typeExp, OpCodes.Ldc_I4_1);
+                ilGen.Emit(typeExp, OpCodes.Xor);
+                result.Pop(this, typeExp);
+                return result;
+            }
+            if(typeExp is TokenTypeExpPar)
+            {
+                return GenerateFromTypeExp(val, ((TokenTypeExpPar)typeExp).typeExp);
+            }
+            if(typeExp is TokenTypeExpType)
+            {
+                CompValuTemp result = new CompValuTemp(tokenTypeBool, this);
+                val.PushVal(this, typeExp);
+                ilGen.Emit(typeExp, OpCodes.Isinst, ((TokenTypeExpType)typeExp).typeToken.ToSysType());
+                ilGen.Emit(typeExp, OpCodes.Ldnull);
+                ilGen.Emit(typeExp, OpCodes.Ceq);
+                ilGen.Emit(typeExp, OpCodes.Ldc_I4_1);
+                ilGen.Emit(typeExp, OpCodes.Xor);
+                result.Pop(this, typeExp);
+                return result;
+            }
+            if(typeExp is TokenTypeExpUndef)
+            {
+                CompValuTemp result = new CompValuTemp(tokenTypeBool, this);
+                val.PushVal(this, typeExp);
+                ilGen.Emit(typeExp, OpCodes.Ldnull);
+                ilGen.Emit(typeExp, OpCodes.Ceq);
+                result.Pop(this, typeExp);
+                return result;
+            }
+            throw new Exception("unknown TokenTypeExp type " + typeExp.GetType());
+        }
+
+        /**
+         * @brief Push the default (null) value for a particular variable
+         * @param var = variable to get the default value for
+         * @returns with value pushed on stack
+         */
+        public void PushVarDefaultValue(TokenDeclVar var)
+        {
+            PushDefaultValue(var.type);
+        }
+        public void PushDefaultValue(TokenType type)
+        {
+            if(type is TokenTypeArray)
+            {
+                PushXMRInst();                // instance
+                ilGen.Emit(type, OpCodes.Newobj, xmrArrayConstructorInfo);
+                return;
+            }
+            if(type is TokenTypeChar)
+            {
+                ilGen.Emit(type, OpCodes.Ldc_I4_0);
+                return;
+            }
+            if(type is TokenTypeList)
+            {
+                ilGen.Emit(type, OpCodes.Ldc_I4_0);
+                ilGen.Emit(type, OpCodes.Newarr, typeof(object));
+                ilGen.Emit(type, OpCodes.Newobj, lslListConstructorInfo);
+                return;
+            }
+            if(type is TokenTypeRot)
+            {
+                // Mono is tOO stOOpid to allow: ilGen.Emit (OpCodes.Ldsfld, zeroRotationFieldInfo);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.x);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.y);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.z);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_ROTATION.s);
+                ilGen.Emit(type, OpCodes.Newobj, lslRotationConstructorInfo);
+                return;
+            }
+            if((type is TokenTypeKey) || (type is TokenTypeStr))
+            {
+                ilGen.Emit(type, OpCodes.Ldstr, "");
+                return;
+            }
+            if(type is TokenTypeVec)
+            {
+                // Mono is tOO stOOpid to allow: ilGen.Emit (OpCodes.Ldsfld, zeroVectorFieldInfo);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.x);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.y);
+                ilGen.Emit(type, OpCodes.Ldc_R8, ScriptBaseClass.ZERO_VECTOR.z);
+                ilGen.Emit(type, OpCodes.Newobj, lslVectorConstructorInfo);
+                return;
+            }
+            if(type is TokenTypeInt)
+            {
+                ilGen.Emit(type, OpCodes.Ldc_I4_0);
+                return;
+            }
+            if(type is TokenTypeFloat)
+            {
+                ilGen.Emit(type, OpCodes.Ldc_R4, 0.0f);
+                return;
+            }
+
+            /*
+             * Default for 'object' type is 'undef'.
+             * Likewise for script-defined classes and interfaces.
+             */
+            if((type is TokenTypeObject) || (type is TokenTypeSDTypeClass) || (type is TokenTypeSDTypeInterface) || (type is TokenTypeExc))
+            {
+                ilGen.Emit(type, OpCodes.Ldnull);
+                return;
+            }
+
+            /*
+             * Void is pushed as the default return value of a void function.
+             * So just push nothing as expected of void functions.
+             */
+            if(type is TokenTypeVoid)
+            {
+                return;
+            }
+
+            /*
+             * Default for 'delegate' type is 'undef'.
+             */
+            if(type is TokenTypeSDTypeDelegate)
+            {
+                ilGen.Emit(type, OpCodes.Ldnull);
+                return;
+            }
+
+            throw new Exception("unknown type " + type.GetType().ToString());
+        }
+
+        /**
+         * @brief Determine if the expression has a constant boolean value
+         *        and if so, if the value is true or false.
+         * @param expr = expression to evaluate
+         * @returns true: expression is contant and has boolean value true
+         *         false: otherwise
+         */
+        private bool IsConstBoolExprTrue(CompValu expr)
+        {
+            bool constVal;
+            return IsConstBoolExpr(expr, out constVal) && constVal;
+        }
+
+        private bool IsConstBoolExpr(CompValu expr, out bool constVal)
+        {
+            if(expr is CompValuChar)
+            {
+                constVal = ((CompValuChar)expr).x != 0;
+                return true;
+            }
+            if(expr is CompValuFloat)
+            {
+                constVal = ((CompValuFloat)expr).x != (double)0;
+                return true;
+            }
+            if(expr is CompValuInteger)
+            {
+                constVal = ((CompValuInteger)expr).x != 0;
+                return true;
+            }
+            if(expr is CompValuString)
+            {
+                string s = ((CompValuString)expr).x;
+                constVal = s != "";
+                if(constVal && (expr.type is TokenTypeKey))
+                {
+                    constVal = s != ScriptBaseClass.NULL_KEY;
+                }
+                return true;
+            }
+
+            constVal = false;
+            return false;
+        }
+
+        /**
+         * @brief Determine if the expression has a constant integer value
+         *        and if so, return the integer value.
+         * @param expr = expression to evaluate
+         * @returns true: expression is contant and has integer value
+         *         false: otherwise
+         */
+        private bool IsConstIntExpr(CompValu expr, out int constVal)
+        {
+            if(expr is CompValuChar)
+            {
+                constVal = (int)((CompValuChar)expr).x;
+                return true;
+            }
+            if(expr is CompValuInteger)
+            {
+                constVal = ((CompValuInteger)expr).x;
+                return true;
+            }
+
+            constVal = 0;
+            return false;
+        }
+
+        /**
+         * @brief Determine if the expression has a constant string value
+         *        and if so, return the string value.
+         * @param expr = expression to evaluate
+         * @returns true: expression is contant and has string value
+         *         false: otherwise
+         */
+        private bool IsConstStrExpr(CompValu expr, out string constVal)
+        {
+            if(expr is CompValuString)
+            {
+                constVal = ((CompValuString)expr).x;
+                return true;
+            }
+            constVal = "";
+            return false;
+        }
+
+        /**
+         * @brief create table of legal event handler prototypes.
+         *        This is used to make sure script's event handler declrations are valid.
+         */
+        private static VarDict CreateLegalEventHandlers()
+        {
+            /*
+             * Get handler prototypes with full argument lists.
+             */
+            VarDict leh = new InternalFuncDict(typeof(IEventHandlers), false);
+
+            /*
+             * We want the scripts to be able to declare their handlers with
+             * fewer arguments than the full argument lists.  So define additional 
+             * prototypes with fewer arguments.
+             */
+            TokenDeclVar[] fullArgProtos = new TokenDeclVar[leh.Count];
+            int i = 0;
+            foreach(TokenDeclVar fap in leh)
+                fullArgProtos[i++] = fap;
+
+            foreach(TokenDeclVar fap in fullArgProtos)
+            {
+                TokenArgDecl fal = fap.argDecl;
+                int fullArgCount = fal.vars.Length;
+                for(i = 0; i < fullArgCount; i++)
+                {
+                    TokenArgDecl shortArgList = new TokenArgDecl(null);
+                    for(int j = 0; j < i; j++)
+                    {
+                        TokenDeclVar var = fal.vars[j];
+                        shortArgList.AddArg(var.type, var.name);
+                    }
+                    TokenDeclVar shortArgProto = new TokenDeclVar(null, null, null);
+                    shortArgProto.name = new TokenName(null, fap.GetSimpleName());
+                    shortArgProto.retType = fap.retType;
+                    shortArgProto.argDecl = shortArgList;
+                    leh.AddEntry(shortArgProto);
+                }
+            }
+
+            return leh;
+        }
+
+        /**
+         * @brief Emit a call to CheckRun(), (voluntary multitasking switch)
+         */
+        public void EmitCallCheckRun(Token errorAt, bool stack)
+        {
+            if(curDeclFunc.IsFuncTrivial(this))
+                throw new Exception(curDeclFunc.fullName + " is supposed to be trivial");
+            new CallLabel(this, errorAt);                               // jump here when stack restored
+            PushXMRInst();                                              // instance
+            ilGen.Emit(errorAt, OpCodes.Call, stack ? checkRunStackMethInfo : checkRunQuickMethInfo);
+            openCallLabel = null;
+        }
+
+        /**
+         * @brief Emit code to push a callNo var on the stack.
+         */
+        public void GetCallNo(Token errorAt, ScriptMyLocal callNoVar)
+        {
+            ilGen.Emit(errorAt, OpCodes.Ldloc, callNoVar);
+            //ilGen.Emit (errorAt, OpCodes.Ldloca, callNoVar);
+            //ilGen.Emit (errorAt, OpCodes.Volatile);
+            //ilGen.Emit (errorAt, OpCodes.Ldind_I4);
+        }
+        public void GetCallNo(Token errorAt, CompValu callNoVar)
+        {
+            callNoVar.PushVal(this, errorAt);
+            //callNoVar.PushRef (this, errorAt);
+            //ilGen.Emit (errorAt, OpCodes.Volatile);
+            //ilGen.Emit (errorAt, OpCodes.Ldind_I4);
+        }
+
+        /**
+         * @brief Emit code to set a callNo var to a given constant.
+         */
+        public void SetCallNo(Token errorAt, ScriptMyLocal callNoVar, int val)
+        {
+            ilGen.Emit(errorAt, OpCodes.Ldc_I4, val);
+            ilGen.Emit(errorAt, OpCodes.Stloc, callNoVar);
+            //ilGen.Emit (errorAt, OpCodes.Ldloca, callNoVar);
+            //ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
+            //ilGen.Emit (errorAt, OpCodes.Volatile);
+            //ilGen.Emit (errorAt, OpCodes.Stind_I4);
+        }
+        public void SetCallNo(Token errorAt, CompValu callNoVar, int val)
+        {
+            callNoVar.PopPre(this, errorAt);
+            ilGen.Emit(errorAt, OpCodes.Ldc_I4, val);
+            callNoVar.PopPost(this, errorAt);
+            //callNoVar.PushRef (this, errorAt);
+            //ilGen.Emit (errorAt, OpCodes.Ldc_I4, val);
+            //ilGen.Emit (errorAt, OpCodes.Volatile);
+            //ilGen.Emit (errorAt, OpCodes.Stind_I4);
+        }
+
+        /**
+         * @brief handle a unary operator, such as -x.
+         */
+        private CompValu UnOpGenerate(CompValu inRVal, Token opcode)
+        {
+            /*
+             * - Negate
+             */
+            if(opcode is TokenKwSub)
+            {
+                if(inRVal.type is TokenTypeFloat)
+                {
+                    CompValuTemp outRVal = new CompValuTemp(new TokenTypeFloat(opcode), this);
+                    inRVal.PushVal(this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
+                    ilGen.Emit(opcode, OpCodes.Neg);     // compute the negative
+                    outRVal.Pop(this, opcode);           // pop into result
+                    return outRVal;                       // tell caller where we put it
+                }
+                if(inRVal.type is TokenTypeInt)
+                {
+                    CompValuTemp outRVal = new CompValuTemp(new TokenTypeInt(opcode), this);
+                    inRVal.PushVal(this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
+                    ilGen.Emit(opcode, OpCodes.Neg);     // compute the negative
+                    outRVal.Pop(this, opcode);           // pop into result
+                    return outRVal;                       // tell caller where we put it
+                }
+                if(inRVal.type is TokenTypeRot)
+                {
+                    CompValuTemp outRVal = new CompValuTemp(inRVal.type, this);
+                    inRVal.PushVal(this, opcode);        // push rotation, then call negate routine
+                    ilGen.Emit(opcode, OpCodes.Call, lslRotationNegateMethodInfo);
+                    outRVal.Pop(this, opcode);           // pop into result
+                    return outRVal;                       // tell caller where we put it
+                }
+                if(inRVal.type is TokenTypeVec)
+                {
+                    CompValuTemp outRVal = new CompValuTemp(inRVal.type, this);
+                    inRVal.PushVal(this, opcode);        // push vector, then call negate routine
+                    ilGen.Emit(opcode, OpCodes.Call, lslVectorNegateMethodInfo);
+                    outRVal.Pop(this, opcode);           // pop into result
+                    return outRVal;                       // tell caller where we put it
+                }
+                ErrorMsg(opcode, "can't negate a " + inRVal.type.ToString());
+                return inRVal;
+            }
+
+            /*
+             * ~ Complement (bitwise integer)
+             */
+            if(opcode is TokenKwTilde)
+            {
+                if(inRVal.type is TokenTypeInt)
+                {
+                    CompValuTemp outRVal = new CompValuTemp(new TokenTypeInt(opcode), this);
+                    inRVal.PushVal(this, opcode, outRVal.type);  // push value to negate, make sure not LSL-boxed
+                    ilGen.Emit(opcode, OpCodes.Not);     // compute the complement
+                    outRVal.Pop(this, opcode);           // pop into result
+                    return outRVal;                       // tell caller where we put it
+                }
+                ErrorMsg(opcode, "can't complement a " + inRVal.type.ToString());
+                return inRVal;
+            }
+
+            /*
+             * ! Not (boolean)
+             *
+             * We stuff the 0/1 result in an int because I've seen x+!y in scripts
+             * and we don't want to have to create tables to handle int+bool and
+             * everything like that.
+             */
+            if(opcode is TokenKwExclam)
+            {
+                CompValuTemp outRVal = new CompValuTemp(new TokenTypeInt(opcode), this);
+                inRVal.PushVal(this, opcode, tokenTypeBool);  // anything converts to boolean
+                ilGen.Emit(opcode, OpCodes.Ldc_I4_1);         // then XOR with 1 to flip it
+                ilGen.Emit(opcode, OpCodes.Xor);
+                outRVal.Pop(this, opcode);                    // pop into result
+                return outRVal;                                // tell caller where we put it
+            }
+
+            throw new Exception("unhandled opcode " + opcode.ToString());
+        }
+
+        /**
+         * @brief This is called while trying to compute the value of constant initializers.
+         *        It is passed a name and that name is looked up in the constant tables.
+         */
+        private TokenRVal LookupInitConstants(TokenRVal rVal, ref bool didOne)
+        {
+            /*
+             * If it is a static field of a script-defined type, look it up and hopefully we find a constant there.
+             */
+            TokenDeclVar gblVar;
+            if(rVal is TokenLValSField)
+            {
+                TokenLValSField lvsf = (TokenLValSField)rVal;
+                if(lvsf.baseType is TokenTypeSDTypeClass)
+                {
+                    TokenDeclSDTypeClass sdtClass = ((TokenTypeSDTypeClass)lvsf.baseType).decl;
+                    gblVar = sdtClass.members.FindExact(lvsf.fieldName.val, null);
+                    if(gblVar != null)
+                    {
+                        if(gblVar.constant && (gblVar.init is TokenRValConst))
+                        {
+                            didOne = true;
+                            return gblVar.init;
+                        }
+                    }
+                }
+                return rVal;
+            }
+
+            /*
+             * Only other thing we handle is stand-alone names.
+             */
+            if(!(rVal is TokenLValName))
+                return rVal;
+            string name = ((TokenLValName)rVal).name.val;
+
+            /*
+             * If we are doing the initializations for a script-defined type,
+             * look for the constant among the fields for that type.
+             */
+            if(currentSDTClass != null)
+            {
+                gblVar = currentSDTClass.members.FindExact(name, null);
+                if(gblVar != null)
+                {
+                    if(gblVar.constant && (gblVar.init is TokenRValConst))
+                    {
+                        didOne = true;
+                        return gblVar.init;
+                    }
+                    return rVal;
+                }
+            }
+
+            /*
+             * Look it up as a script-defined global variable.
+             * Then if the variable is defined as a constant and has a constant value,
+             * we are successful.  If it is defined as something else, return failure.
+             */
+            gblVar = tokenScript.variablesStack.FindExact(name, null);
+            if(gblVar != null)
+            {
+                if(gblVar.constant && (gblVar.init is TokenRValConst))
+                {
+                    didOne = true;
+                    return gblVar.init;
+                }
+                return rVal;
+            }
+
+            /*
+             * Maybe it is a built-in symbolic constant.
+             */
+            ScriptConst scriptConst = ScriptConst.Lookup(name);
+            if(scriptConst != null)
+            {
+                rVal = CompValuConst2RValConst(scriptConst.rVal, rVal);
+                if(rVal is TokenRValConst)
+                {
+                    didOne = true;
+                    return rVal;
+                }
+            }
+
+            /*
+             * Don't know what it is, return failure.
+             */
+            return rVal;
+        }
+
+        /**
+         * @brief This is called while trying to compute the value of constant expressions.
+         *        It is passed a name and that name is looked up in the constant tables.
+         */
+        private TokenRVal LookupBodyConstants(TokenRVal rVal, ref bool didOne)
+        {
+            /*
+             * If it is a static field of a script-defined type, look it up and hopefully we find a constant there.
+             */
+            TokenDeclVar gblVar;
+            if(rVal is TokenLValSField)
+            {
+                TokenLValSField lvsf = (TokenLValSField)rVal;
+                if(lvsf.baseType is TokenTypeSDTypeClass)
+                {
+                    TokenDeclSDTypeClass sdtClass = ((TokenTypeSDTypeClass)lvsf.baseType).decl;
+                    gblVar = sdtClass.members.FindExact(lvsf.fieldName.val, null);
+                    if((gblVar != null) && gblVar.constant && (gblVar.init is TokenRValConst))
+                    {
+                        didOne = true;
+                        return gblVar.init;
+                    }
+                }
+                return rVal;
+            }
+
+            /*
+             * Only other thing we handle is stand-alone names.
+             */
+            if(!(rVal is TokenLValName))
+                return rVal;
+            string name = ((TokenLValName)rVal).name.val;
+
+            /*
+             * Scan through the variable stack and hopefully we find a constant there.
+             * But we stop as soon as we get a match because that's what the script is referring to.
+             */
+            CompValu val;
+            for(VarDict vars = ((TokenLValName)rVal).stack; vars != null; vars = vars.outerVarDict)
+            {
+                TokenDeclVar var = vars.FindExact(name, null);
+                if(var != null)
+                {
+                    val = var.location;
+                    goto foundit;
+                }
+
+                TokenDeclSDTypeClass baseClass = vars.thisClass;
+                if(baseClass != null)
+                {
+                    while((baseClass = baseClass.extends) != null)
+                    {
+                        var = baseClass.members.FindExact(name, null);
+                        if(var != null)
+                        {
+                            val = var.location;
+                            goto foundit;
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Maybe it is a built-in symbolic constant.
+             */
+            ScriptConst scriptConst = ScriptConst.Lookup(name);
+            if(scriptConst != null)
+            {
+                val = scriptConst.rVal;
+                goto foundit;
+            }
+
+            /*
+             * Don't know what it is, return failure.
+             */
+            return rVal;
+
+            /*
+             * Found a CompValu.  If it's a simple constant, then use it.
+             * Otherwise tell caller we failed to simplify.
+             */
+            foundit:
+            rVal = CompValuConst2RValConst(val, rVal);
+            if(rVal is TokenRValConst)
+            {
+                didOne = true;
+            }
+            return rVal;
+        }
+
+        private static TokenRVal CompValuConst2RValConst(CompValu val, TokenRVal rVal)
+        {
+            if(val is CompValuChar)
+                rVal = new TokenRValConst(rVal, ((CompValuChar)val).x);
+            if(val is CompValuFloat)
+                rVal = new TokenRValConst(rVal, ((CompValuFloat)val).x);
+            if(val is CompValuInteger)
+                rVal = new TokenRValConst(rVal, ((CompValuInteger)val).x);
+            if(val is CompValuString)
+                rVal = new TokenRValConst(rVal, ((CompValuString)val).x);
+            return rVal;
+        }
+
+        /**
+         * @brief Generate code to push XMRInstanceSuperType pointer on stack.
+         */
+        public void PushXMRInst()
+        {
+            if(instancePointer == null)
+            {
+                ilGen.Emit(null, OpCodes.Ldarg_0);
+            }
+            else
+            {
+                ilGen.Emit(null, OpCodes.Ldloc, instancePointer);
+            }
+        }
+
+        /**
+         * @returns true: Ldarg_0 gives XMRSDTypeClObj pointer
+         *                - this is the case for instance methods
+         *         false: Ldarg_0 gives XMR_Instance pointer
+         *                - this is the case for both global functions and static methods
+         */
+        public bool IsSDTInstMethod()
+        {
+            return (curDeclFunc.sdtClass != null) &&
+                   ((curDeclFunc.sdtFlags & ScriptReduce.SDT_STATIC) == 0);
+        }
+
+        /**
+         * @brief Look for a simply named function or variable (not a field or method)
+         */
+        public TokenDeclVar FindNamedVar(TokenLValName lValName, TokenType[] argsig)
+        {
+            /*
+             * Look in variable stack for the given name.
+             */
+            for(VarDict vars = lValName.stack; vars != null; vars = vars.outerVarDict)
+            {
+
+                // first look for it possibly with an argument signature
+                // so we pick the correct overloaded method
+                TokenDeclVar var = FindSingleMember(vars, lValName.name, argsig);
+                if(var != null)
+                    return var;
+
+                // if that fails, try it without the argument signature.
+                // delegates get entered like any other variable, ie, 
+                // no signature on their name.
+                if(argsig != null)
+                {
+                    var = FindSingleMember(vars, lValName.name, null);
+                    if(var != null)
+                        return var;
+                }
+
+                // if this is the frame for some class members, try searching base class members too
+                TokenDeclSDTypeClass baseClass = vars.thisClass;
+                if(baseClass != null)
+                {
+                    while((baseClass = baseClass.extends) != null)
+                    {
+                        var = FindSingleMember(baseClass.members, lValName.name, argsig);
+                        if(var != null)
+                            return var;
+                        if(argsig != null)
+                        {
+                            var = FindSingleMember(baseClass.members, lValName.name, null);
+                            if(var != null)
+                                return var;
+                        }
+                    }
+                }
+            }
+
+            /*
+             * If not found, try one of the built-in constants or functions.
+             */
+            if(argsig == null)
+            {
+                ScriptConst scriptConst = ScriptConst.Lookup(lValName.name.val);
+                if(scriptConst != null)
+                {
+                    TokenDeclVar var = new TokenDeclVar(lValName.name, null, tokenScript);
+                    var.name = lValName.name;
+                    var.type = scriptConst.rVal.type;
+                    var.location = scriptConst.rVal;
+                    return var;
+                }
+            }
+            else
+            {
+                TokenDeclVar inline = FindSingleMember(TokenDeclInline.inlineFunctions, lValName.name, argsig);
+                if(inline != null)
+                    return inline;
+            }
+
+            return null;
+        }
+
+
+        /**
+         * @brief Find a member of an interface.
+         * @param sdType = interface type
+         * @param name = name of member to find
+         * @param argsig = null: field/property; else: script-visible method argument types
+         * @param baseRVal = pointer to interface object
+         * @returns null: no such member
+         *          else: pointer to member
+         *                baseRVal = possibly modified to point to type-casted interface object
+         */
+        private TokenDeclVar FindInterfaceMember(TokenTypeSDTypeInterface sdtType, TokenName name, TokenType[] argsig, ref CompValu baseRVal)
+        {
+            TokenDeclSDTypeInterface sdtDecl = sdtType.decl;
+            TokenDeclSDTypeInterface impl;
+            TokenDeclVar declVar = sdtDecl.FindIFaceMember(this, name, argsig, out impl);
+            if((declVar != null) && (impl != sdtDecl))
+            {
+
+                /*
+                 * Accessing a method or propterty of another interface that the primary interface says it implements.
+                 * In this case, we have to cast from the primary interface to that secondary interface.
+                 *
+                 * interface IEnumerable {
+                 *     IEnumerator GetEnumerator ();
+                 * }
+                 * interface ICountable : IEnumerable {
+                 *     integer GetCount ();
+                 * }
+                 * class List : ICountable {
+                 *     public GetCount () : ICountable { ... }
+                 *     public GetEnumerator () : IEnumerable { ... }
+                 * }
+                 *
+                 *     ICountable aList = new List ();
+                 *     IEnumerator anEnumer = aList.GetEnumerator ();   << we are here
+                 *                                                      << baseRVal = aList
+                 *                                                      << sdtDecl = ICountable
+                 *                                                      << impl = IEnumerable
+                 *                                                      << name = GetEnumerator
+                 *                                                      << argsig = ()
+                 * So we have to cast aList from ICountable to IEnumerable.
+                 */
+
+                // make type token for the secondary interface type
+                TokenType subIntfType = impl.MakeRefToken(name);
+
+                // make a temp variable of the secondary interface type
+                CompValuTemp castBase = new CompValuTemp(subIntfType, this);
+
+                // output code to cast from the primary interface to the secondary interface
+                // this is 2 basic steps:
+                // 1) cast from primary interface object -> class object
+                //    ...gets it from interfaceObject.delegateArray[0].Target
+                // 2) cast from class object -> secondary interface object
+                //    ...gets it from classObject.sdtcITable[interfaceIndex]
+                baseRVal.PushVal(this, name, subIntfType);
+
+                // save result of casting in temp
+                castBase.Pop(this, name);
+
+                // return temp reference
+                baseRVal = castBase;
+            }
+
+            return declVar;
+        }
+
+        /**
+         * @brief Find a member of a script-defined type class.
+         * @param sdtType = reference to class declaration
+         * @param name = name of member to find
+         * @param argsig = argument signature used to select among overloaded members
+         * @returns null: no such member found
+         *          else: the member found
+         */
+        public TokenDeclVar FindThisMember(TokenTypeSDTypeClass sdtType, TokenName name, TokenType[] argsig)
+        {
+            return FindThisMember(sdtType.decl, name, argsig);
+        }
+        public TokenDeclVar FindThisMember(TokenDeclSDTypeClass sdtDecl, TokenName name, TokenType[] argsig)
+        {
+            for(TokenDeclSDTypeClass sdtd = sdtDecl; sdtd != null; sdtd = sdtd.extends)
+            {
+                TokenDeclVar declVar = FindSingleMember(sdtd.members, name, argsig);
+                if(declVar != null)
+                    return declVar;
+            }
+            return null;
+        }
+
+        /**
+         * @brief Look for a single member that matches the given name and argument signature
+         * @param where = which dictionary to look in
+         * @param name = basic name of the field or method, eg, "Printable"
+         * @param argsig = argument types the method is being called with, eg, "(string)"
+         *                 or null to find a field
+         * @returns null: no member found
+         *          else: the member found
+         */
+        public TokenDeclVar FindSingleMember(VarDict where, TokenName name, TokenType[] argsig)
+        {
+            TokenDeclVar[] members = where.FindCallables(name.val, argsig);
+            if(members == null)
+                return null;
+            if(members.Length > 1)
+            {
+                ErrorMsg(name, "more than one matching member");
+                for(int i = 0; i < members.Length; i++)
+                {
+                    ErrorMsg(members[i], "  " + members[i].argDecl.GetArgSig());
+                }
+            }
+            return members[0];
+        }
+
+        /**
+         * @brief Find an exact function name and argument signature match.
+         *        Also verify that the return value type is an exact match.
+         * @param where = which method dictionary to look in
+         * @param name = basic name of the method, eg, "Printable"
+         * @param ret = expected return value type
+         * @param argsig = argument types the method is being called with, eg, "(string)"
+         * @returns null: no exact match found
+         *          else: the matching function
+         */
+        private TokenDeclVar FindExactWithRet(VarDict where, TokenName name, TokenType ret, TokenType[] argsig)
+        {
+            TokenDeclVar func = where.FindExact(name.val, argsig);
+            if((func != null) && (func.retType.ToString() != ret.ToString()))
+            {
+                ErrorMsg(name, "return type mismatch, have " + func.retType.ToString() + ", expect " + ret.ToString());
+            }
+            if(func != null)
+                CheckAccess(func, name);
+            return func;
+        }
+
+        /**
+         * @brief Check the private/protected/public access flags of a member.
+         */
+        private void CheckAccess(TokenDeclVar var, Token errorAt)
+        {
+            TokenDeclSDType nested;
+            TokenDeclSDType definedBy = var.sdtClass;
+            TokenDeclSDType accessedBy = curDeclFunc.sdtClass;
+
+            /*******************************\
+             *  Check member-level access  *
+            \*******************************/
+
+            /*
+             * Note that if accessedBy is null, ie, accessing from global function (or event handlers),
+             * anything tagged as SDT_PRIVATE or SDT_PROTECTED will fail.
+             */
+
+            /*
+             * Private means accessed by the class that defined the member or accessed by a nested class
+             * of the class that defined the member.
+             */
+            if((var.sdtFlags & ScriptReduce.SDT_PRIVATE) != 0)
+            {
+                for(nested = accessedBy; nested != null; nested = nested.outerSDType)
+                {
+                    if(nested == definedBy)
+                        goto acc1ok;
+                }
+                ErrorMsg(errorAt, "private member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName);
+                return;
+            }
+
+            /*
+             * Protected means:
+             *   If being accessed by an inner class, the inner class has access to it if the inner class derives 
+             *   from the declaring class.  It also has access to it if an outer class derives from the declaring 
+             *   class.
+             */
+            if((var.sdtFlags & ScriptReduce.SDT_PROTECTED) != 0)
+            {
+                for(nested = accessedBy; nested != null; nested = nested.outerSDType)
+                {
+                    for(TokenDeclSDType rootward = nested; rootward != null; rootward = rootward.extends)
+                    {
+                        if(rootward == definedBy)
+                            goto acc1ok;
+                    }
+                }
+                ErrorMsg(errorAt, "protected member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName);
+                return;
+            }
+            acc1ok:
+
+            /******************************\
+             *  Check class-level access  *
+            \******************************/
+
+            /*
+             * If being accessed by same or inner class than where defined, it is ok.
+             *
+             *      class DefiningClass {
+             *          varBeingAccessed;
+             *                         .
+             *                         .
+             *                         .
+             *                  class AccessingClass {
+             *                      functionDoingAccess() { }
+             *                  }
+             *                         .
+             *                         .
+             *                         .
+             *      }
+             */
+            nested = accessedBy;
+            while(true)
+            {
+                if(nested == definedBy)
+                    return;
+                if(nested == null)
+                    break;
+                nested = (TokenDeclSDTypeClass)nested.outerSDType;
+            }
+
+            /*
+             * It is being accessed by an outer class than where defined, 
+             * check for a 'private' or 'protected' class tag that blocks.
+             */
+            do
+            {
+
+                /*
+                 * If the field's class is defined directly inside the accessing class,
+                 * access is allowed regardless of class-level private or protected tags.
+                 *
+                 *      class AccessingClass {
+                 *          functionDoingAccess() { }
+                 *          class DefiningClass {
+                 *              varBeingAccessed;
+                 *          }
+                 *      }
+                 */
+                if(definedBy.outerSDType == accessedBy)
+                    return;
+
+                /*
+                 * If the field's class is defined two or more levels inside the accessing class, 
+                 * access is denied if the defining class is tagged private.
+                 *
+                 *      class AccessingClass {
+                 *          functionDoingAccess() { }
+                 *                         .
+                 *                         .
+                 *                         .
+                 *                  class IntermediateClass {
+                 *                      private class DefiningClass {
+                 *                          varBeingAccessed;
+                 *                      }
+                 *                  }
+                 *                         .
+                 *                         .
+                 *                         .
+                 *      }
+                 */
+                if((definedBy.accessLevel & ScriptReduce.SDT_PRIVATE) != 0)
+                {
+                    ErrorMsg(errorAt, "member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName +
+                                       " because of private class " + definedBy.longName.val);
+                    return;
+                }
+
+                /*
+                 * Likewise, if DefiningClass is tagged protected, the AccessingClass must derive from the
+                 * IntermediateClass or access is denied.
+                 */
+                if((definedBy.accessLevel & ScriptReduce.SDT_PROTECTED) != 0)
+                {
+                    for(TokenDeclSDType extends = accessedBy; extends != definedBy.outerSDType; extends = extends.extends)
+                    {
+                        if(extends == null)
+                        {
+                            ErrorMsg(errorAt, "member " + var.fullName + " cannot be accessed by " + curDeclFunc.fullName +
+                                               " because of protected class " + definedBy.longName.val);
+                            return;
+                        }
+                    }
+                }
+
+                /*
+                 * Check next outer level.
+                 */
+                definedBy = definedBy.outerSDType;
+            } while(definedBy != null);
+        }
+
+        /**
+         * @brief Convert a list of argument types to printable string, eg, "(list,string,float,integer)"
+         *        If given a null, return "" indicating it is a field not a method
+         */
+        public static string ArgSigString(TokenType[] argsig)
+        {
+            if(argsig == null)
+                return "";
+            StringBuilder sb = new StringBuilder("(");
+            for(int i = 0; i < argsig.Length; i++)
+            {
+                if(i > 0)
+                    sb.Append(",");
+                sb.Append(argsig[i].ToString());
+            }
+            sb.Append(")");
+            return sb.ToString();
+        }
+
+        /**
+         * @brief output error message and remember that we did
+         */
+        public void ErrorMsg(Token token, string message)
+        {
+            if((token == null) || (token.emsg == null))
+                token = errorMessageToken;
+            if(!youveAnError || (token.file != lastErrorFile) || (token.line > lastErrorLine))
+            {
+                token.ErrorMsg(message);
+                youveAnError = true;
+                lastErrorFile = token.file;
+                lastErrorLine = token.line;
+            }
+        }
+
+        /**
+         * @brief Find a private static method.
+         * @param owner = class the method is part of
+         * @param name = name of method to find
+         * @param args = array of argument types
+         * @returns pointer to method
+         */
+        public static MethodInfo GetStaticMethod(Type owner, string name, Type[] args)
+        {
+            MethodInfo mi = owner.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
+            if(mi == null)
+            {
+                throw new Exception("undefined method " + owner.ToString() + "." + name);
+            }
+            return mi;
+        }
+
+        // http://wiki.secondlife.com/wiki/Rotation 'negate a rotation' says just negate .s component
+        // but http://wiki.secondlife.com/wiki/LSL_Language_Test (lslangtest1.lsl) says negate all 4 values
+        public static LSL_Rotation LSLRotationNegate(LSL_Rotation r)
+        {
+            return new LSL_Rotation(-r.x, -r.y, -r.z, -r.s);
+        }
+        public static LSL_Vector LSLVectorNegate(LSL_Vector v)
+        {
+            return -v;
+        }
+        public static string CatchExcToStr(Exception exc)
+        {
+            return exc.ToString();
+        }
+        //public static void       ConsoleWrite      (string str)     { Console.Write(str); }
+
+        /**
+         * @brief Defines an internal label that is used as a target for 'break' and 'continue' statements.
+         */
+        private class BreakContTarg
+        {
+            public bool used;
+            public ScriptMyLabel label;
+            public TokenStmtBlock block;
+
+            public BreakContTarg(ScriptCodeGen scg, string name)
+            {
+                used = false;                         // assume it isn't referenced at all
+                label = scg.ilGen.DefineLabel(name);  // label that the break/continue jumps to
+                block = scg.curStmtBlock;              // { ... } that the break/continue label is in
+            }
+        }
+    }
+
+    /**
+     * @brief Marker interface indicates an exception that can't be caught by a script-level try/catch.
+     */
+    public interface IXMRUncatchable
+    {
+    }
+
+    /**
+     * @brief Thrown by a script when it attempts to change to an undefined state.
+     * These can be detected at compile time but the moron XEngine compiles
+     * such things, so we compile them as runtime errors.
+     */
+    [SerializableAttribute]
+    public class ScriptUndefinedStateException: Exception, ISerializable
+    {
+        public string stateName;
+        public ScriptUndefinedStateException(string stateName) : base("undefined state " + stateName)
+        {
+            this.stateName = stateName;
+        }
+        protected ScriptUndefinedStateException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+
+    /**
+     * @brief Created by a throw statement.
+     */
+    [SerializableAttribute]
+    public class ScriptThrownException: Exception, ISerializable
+    {
+        public object thrown;
+
+        /**
+         * @brief Called by a throw statement to wrap the object in a unique
+         *        tag that capable of capturing a stack trace.  Script can 
+         *        unwrap it by calling xmrExceptionThrownValue().
+         */
+        public static Exception Wrap(object thrown)
+        {
+            return new ScriptThrownException(thrown);
+        }
+        private ScriptThrownException(object thrown) : base(thrown.ToString())
+        {
+            this.thrown = thrown;
+        }
+
+        /**
+         * @brief Used by serialization/deserialization.
+         */
+        protected ScriptThrownException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+
+    /**
+     * @brief Thrown by a script when it attempts to change to a defined state.
+     */
+    [SerializableAttribute]
+    public class ScriptChangeStateException: Exception, ISerializable, IXMRUncatchable
+    {
+        public int newState;
+        public ScriptChangeStateException(int newState)
+        {
+            this.newState = newState;
+        }
+        protected ScriptChangeStateException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+
+    /**
+     * @brief We are restoring to the body of a catch { } so we need to 
+     *        wrap the original exception in an outer exception, so the 
+     *        system won't try to refill the stack trace.
+     *
+     *        We don't mark this one serializable as it should never get 
+     *        serialized out.  It only lives from the throw to the very 
+     *        beginning of the catch handler where it is promptly unwrapped.
+     *        No CheckRun() call can possibly intervene.
+     */
+    public class ScriptRestoreCatchException: Exception
+    {
+
+        // old code uses these
+        private object e;
+        public ScriptRestoreCatchException(object e)
+        {
+            this.e = e;
+        }
+        public static object Unwrap(object o)
+        {
+            if(o is IXMRUncatchable)
+                return null;
+            if(o is ScriptRestoreCatchException)
+                return ((ScriptRestoreCatchException)o).e;
+            return o;
+        }
+
+        // new code uses these
+        private Exception ee;
+        public ScriptRestoreCatchException(Exception ee)
+        {
+            this.ee = ee;
+        }
+        public static Exception Unwrap(Exception oo)
+        {
+            if(oo is IXMRUncatchable)
+                return null;
+            if(oo is ScriptRestoreCatchException)
+                return ((ScriptRestoreCatchException)oo).ee;
+            return oo;
+        }
+    }
+
+    [SerializableAttribute]
+    public class ScriptBadCallNoException: Exception
+    {
+        public ScriptBadCallNoException(int callNo) : base("bad callNo " + callNo) { }
+        protected ScriptBadCallNoException(SerializationInfo info, StreamingContext context) : base(info, context)
+        {
+        }
+    }
+
+    public class CVVMismatchException: Exception
+    {
+        public int oldcvv;
+        public int newcvv;
+
+        public CVVMismatchException(int oldcvv, int newcvv) : base("object version is " + oldcvv.ToString() +
+                                                             " but accept only " + newcvv.ToString())
+        {
+            this.oldcvv = oldcvv;
+            this.newcvv = newcvv;
+        }
+    }
+}

+ 3105 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs

@@ -0,0 +1,3105 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+
+/**
+ * @brief Wrapper class for ScriptMyILGen to do simple optimizations.
+ *        The main one is to figure out which locals are active at the labels
+ *        so the stack capture/restore code doesn't have to do everything.
+ *        Second is it removes unnecessary back-to-back stloc/ldloc's.
+ */
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    /**
+     * @brief This is a list that keeps track of types pushed on the evaluation stack.
+     */
+    public class StackDepth: List<Type>
+    {
+        public List<bool> isBoxeds = new List<bool>();
+
+        /**
+         * @brief Clear both stacks.
+         */
+        public new void Clear()
+        {
+            base.Clear();
+            isBoxeds.Clear();
+        }
+
+        /**
+         * @brief Pop call parameters and validate the types.
+         */
+        public void Pop(ParameterInfo[] pis)
+        {
+            int n = pis.Length;
+            int c = this.Count;
+            if(n > c)
+                throw new Exception("stack going negative");
+            for(int i = n; --i >= 0;)
+            {
+                --c;
+                ExpectedVsOnStack(pis[i].ParameterType, this[c], isBoxeds[c]);
+            }
+            Pop(n);
+        }
+
+        /**
+         * @brief Pop values and validate the types.
+         */
+        public void Pop(Type[] ts)
+        {
+            int n = ts.Length;
+            int c = this.Count;
+            if(n > c)
+                throw new Exception("stack going negative");
+            for(int i = ts.Length; --i >= 0;)
+            {
+                --c;
+                ExpectedVsOnStack(ts[i], this[c], isBoxeds[c]);
+            }
+            Pop(n);
+        }
+
+        /**
+         * @brief Pop a single value and validate the type.
+         */
+        public void Pop(Type t)
+        {
+            int c = this.Count;
+            if(c < 1)
+                throw new Exception("stack going negative");
+            ExpectedVsOnStack(t, this[c - 1], isBoxeds[c - 1]);
+            Pop(1);
+        }
+
+        /**
+         * @brief Pop a single value and validate that it is a numeric type.
+         */
+        public Type PopNumVal()
+        {
+            int c = this.Count;
+            if(c < 1)
+                throw new Exception("stack going negative");
+            Type st = this[--c];
+            if(st == null)
+            {
+                throw new Exception("stack has null, expecting a numeric");
+            }
+            if(isBoxeds[c])
+            {
+                throw new Exception("stack is boxed " + st.Name + ", expecting a numeric");
+            }
+            if((st != typeof(bool)) && (st != typeof(char)) && (st != typeof(int)) &&
+                (st != typeof(long)) && (st != typeof(float)) && (st != typeof(double)))
+            {
+                throw new Exception("stack has " + st.Name + ", expecting a numeric");
+            }
+            return Pop(1);
+        }
+
+        /**
+         * @brief Pop a single value and validate that it is a reference type
+         */
+        public Type PopRef()
+        {
+            int c = this.Count;
+            if(c < 1)
+                throw new Exception("stack going negative");
+            Type st = this[--c];
+            if((st != null) && !isBoxeds[c] && st.IsValueType)
+            {
+                throw new Exception("stack has " + st.Name + ", expecting a ref type");
+            }
+            return Pop(1);
+        }
+
+        /**
+         * @brief Pop a single value and validate that it is a value type
+         */
+        public Type PopValue()
+        {
+            int c = this.Count;
+            if(c < 1)
+                throw new Exception("stack going negative");
+            Type st = this[--c];
+            if(st == null)
+            {
+                throw new Exception("stack has null, expecting a value type");
+            }
+            if(!st.IsValueType)
+            {
+                throw new Exception("stack has " + st.Name + ", expecting a value type");
+            }
+            if(isBoxeds[c])
+            {
+                throw new Exception("stack has boxed " + st.Name + ", expecting an unboxed value type");
+            }
+            return Pop(1);
+        }
+
+        // ex = what is expected to be on stack
+        // st = what is actually on stack (null for ldnull)
+        // stBoxed = stack value is boxed
+        public static void ExpectedVsOnStack(Type ex, Type st, bool stBoxed)
+        {
+            // ldnull pushed on stack can go into any pointer type
+            if(st == null)
+            {
+                if(ex.IsByRef || ex.IsPointer || ex.IsClass || ex.IsInterface)
+                    return;
+                throw new Exception("stack has null, expect " + ex.Name);
+            }
+
+            // simple case of expecting an object
+            // ...so the stack can have object,string, etc
+            // but we cant allow int = boxed int here
+            if(ex.IsAssignableFrom(st) && !stBoxed)
+                return;
+
+            // case of expecting an enum on the stack
+            // but all the CIL code knows about are ints etc
+            // so convert the Enum type to integer or whatever
+            // and that should be assignable from what's on stack
+            if(ex.IsEnum && typeof(int).IsAssignableFrom(st))
+                return;
+
+            // bool, char, int are interchangeable on the stack
+            if((ex == typeof(bool) || ex == typeof(char) || ex == typeof(int)) &&
+                (st == typeof(bool) || st == typeof(char) || st == typeof(int)))
+                return;
+
+            // float and double are interchangeable on the stack
+            if((ex == typeof(float) || ex == typeof(double)) &&
+                (st == typeof(float) || st == typeof(double)))
+                return;
+
+            // object can accept any boxed type
+            if((ex == typeof(object)) && stBoxed)
+                return;
+
+            // otherwise, it is disallowed
+            throw new Exception("stack has " + StackTypeString(st, stBoxed) + ", expect " + ex.Name);
+        }
+
+        /**
+         * @brief Pop values without any validation.
+         */
+        public Type Pop(int n)
+        {
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+            Type lastPopped = null;
+            int c = this.Count;
+            if(n > c)
+                throw new Exception("stack going negative");
+            if(n > 0)
+            {
+                lastPopped = this[c - n];
+                this.RemoveRange(c - n, n);
+                isBoxeds.RemoveRange(c - n, n);
+            }
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+            return lastPopped;
+        }
+
+        /**
+         * @brief Peek at the n'th stack value.
+         *        n = 0 : top of stack
+         *            1 : next to top
+         *                ...
+         */
+        public Type Peek(int n)
+        {
+            int c = this.Count;
+            if(n > c - 1)
+                throw new Exception("stack going negative");
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+            return this[c - n - 1];
+        }
+        public bool PeekBoxed(int n)
+        {
+            int c = isBoxeds.Count;
+            if(n > c - 1)
+                throw new Exception("stack going negative");
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+            return isBoxeds[c - n - 1];
+        }
+
+        /**
+         * @brief Push a single value of the given type.
+         */
+        public void Push(Type t)
+        {
+            Push(t, false);
+        }
+        public void Push(Type t, bool isBoxed)
+        {
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+            this.Add(t);
+            isBoxeds.Add(isBoxed);
+        }
+
+        /**
+         * @brief See if the types at a given label exactly match those on the stack.
+         *        We should have the stack types be the same no matter how we branched 
+         *        or fell through to a particular label.
+         */
+        public void Matches(ScriptMyLabel label)
+        {
+            Type[] ts = label.stackDepth;
+            bool[] tsBoxeds = label.stackBoxeds;
+            int i;
+
+            if(this.Count != isBoxeds.Count)
+                throw new Exception("isBoxeds count bad");
+
+            if(ts == null)
+            {
+                label.stackDepth = this.ToArray();
+                label.stackBoxeds = isBoxeds.ToArray();
+            }
+            else if(ts.Length != this.Count)
+            {
+                throw new Exception("stack depth mismatch");
+            }
+            else
+            {
+                for(i = this.Count; --i >= 0;)
+                {
+                    if(tsBoxeds[i] != this.isBoxeds[i])
+                        goto mismatch;
+                    if(ts[i] == this[i])
+                        continue;
+                    if((ts[i] == typeof(bool) || ts[i] == typeof(char) || ts[i] == typeof(int)) &&
+                        (this[i] == typeof(bool) || this[i] == typeof(char) || this[i] == typeof(int)))
+                        continue;
+                    if((ts[i] == typeof(double) || ts[i] == typeof(float)) &&
+                        (this[i] == typeof(double) || this[i] == typeof(float)))
+                        continue;
+                    goto mismatch;
+                }
+            }
+            return;
+            mismatch:
+            throw new Exception("stack type mismatch: " + StackTypeString(ts[i], tsBoxeds[i]) + " vs " + StackTypeString(this[i], this.isBoxeds[i]));
+        }
+
+        private static string StackTypeString(Type ts, bool isBoxed)
+        {
+            if(!isBoxed)
+                return ts.Name;
+            return "[" + ts.Name + "]";
+        }
+    }
+
+    /**
+     * @brief One of these per opcode and label in the function plus other misc markers.
+     *        They form the CIL instruction stream of the function.
+     */
+    public abstract class GraphNode
+    {
+        private static readonly bool DEBUG = false;
+
+        public const int OPINDENT = 4;
+        public const int OPDEBLEN = 12;
+
+        public ScriptCollector coll;
+        public GraphNodeBeginExceptionBlock tryBlock;  // start of enclosing try block
+                                                       // valid in the try section
+                                                       // null in the catch/finally sections
+                                                       // null outside of try block
+                                                       // for the try node itself, links to outer try block
+        public GraphNodeBeginExceptionBlock excBlock;  // start of enclosing try block
+                                                       // valid in the try/catch/finally sections
+                                                       // null outside of try/catch/finally block
+                                                       // for the try node itself, links to outer try block
+
+        /*
+         * List of nodes in order as originally given.
+         */
+        public GraphNode nextLin, prevLin;
+        public int linSeqNo;
+
+        /**
+         * @brief Save pointer to collector.
+         */
+        public GraphNode(ScriptCollector coll)
+        {
+            this.coll = coll;
+        }
+
+        /**
+         * @brief Chain graph node to end of linear list.
+         */
+        public virtual void ChainLin()
+        {
+            coll.lastLin.nextLin = this;
+            this.prevLin = coll.lastLin;
+            coll.lastLin = this;
+            this.tryBlock = coll.curTryBlock;
+            this.excBlock = coll.curExcBlock;
+
+            if(DEBUG)
+            {
+                StringBuilder sb = new StringBuilder("ChainLin*:");
+                sb.Append(coll.stackDepth.Count.ToString("D2"));
+                sb.Append(' ');
+                this.DebString(sb);
+                Console.WriteLine(sb.ToString());
+            }
+        }
+
+        /**
+         * @brief Append full info to debugging string for printing out the instruction.
+         */
+        public void DebStringExt(StringBuilder sb)
+        {
+            int x = sb.Length;
+            sb.Append(this.linSeqNo.ToString().PadLeft(5));
+            sb.Append(": ");
+            this.DebString(sb);
+
+            if(this.ReadsLocal() != null)
+                ScriptCollector.PadToLength(sb, x + 60, " [read]");
+            if(this.WritesLocal() != null)
+                ScriptCollector.PadToLength(sb, x + 68, " [write]");
+            ScriptCollector.PadToLength(sb, x + 72, " ->");
+            bool first = true;
+            foreach(GraphNode nn in this.NextNodes)
+            {
+                if(first)
+                {
+                    sb.Append(nn.linSeqNo.ToString().PadLeft(5));
+                    first = false;
+                }
+                else
+                {
+                    sb.Append(',');
+                    sb.Append(nn.linSeqNo);
+                }
+            }
+        }
+
+        /**
+         * @brief See if it's possible for it to fall through to the next inline (nextLin) instruction.
+         */
+        public virtual bool CanFallThrough()
+        {
+            return true;
+        }
+
+        /**
+         * @brief Append to debugging string for printing out the instruction.
+         */
+        public abstract void DebString(StringBuilder sb);
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            this.DebString(sb);
+            return sb.ToString();
+        }
+
+        /**
+         * @brief See if this instruction reads a local variable.
+         */
+        public virtual ScriptMyLocal ReadsLocal()
+        {
+            return null;
+        }
+
+        /**
+         * @brief See if this instruction writes a local variable.
+         */
+        public virtual ScriptMyLocal WritesLocal()
+        {
+            return null;
+        }
+
+        /**
+         * @brief Write this instruction out to the wrapped object file.
+         */
+        public abstract void WriteOutOne(ScriptMyILGen ilGen);
+
+        /**
+         * @brief Iterate through all the possible next nodes, including the next inline node, if any.
+         *        The next inline code is excluded if the instruction never falls through, eg, return, unconditional branch.
+         *        It includes a possible conditional branch to the beginning of the corresponding catch/finally of every 
+         *        instruction in a try section.
+         */
+        private System.Collections.Generic.IEnumerable<GraphNode> nextNodes, nextNodesCatchFinally;
+        public System.Collections.Generic.IEnumerable<GraphNode> NextNodes
+        {
+            get
+            {
+                if(nextNodes == null)
+                {
+                    nextNodes = GetNNEnumerable();
+                    nextNodesCatchFinally = new NNEnumerableCatchFinally(this);
+                }
+                return nextNodesCatchFinally;
+            }
+        }
+
+        /**
+         * @brief This acts as a wrapper around all the other NNEnumerable's below.
+         *        It assumes every instruction in a try { } can throw an exception so it 
+         *        says that every instruction in a try { } can conditionally branch to 
+         *        the beginning of the corresponding catch { } or finally { }.
+         */
+        private class NNEnumerableCatchFinally: System.Collections.Generic.IEnumerable<GraphNode>
+        {
+            private GraphNode gn;
+            public NNEnumerableCatchFinally(GraphNode gn)
+            {
+                this.gn = gn;
+            }
+            System.Collections.Generic.IEnumerator<GraphNode> System.Collections.Generic.IEnumerable<GraphNode>.GetEnumerator()
+            {
+                return new NNEnumeratorCatchFinally(gn);
+            }
+            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+            {
+                return new NNEnumeratorCatchFinally(gn);
+            }
+        }
+        private class NNEnumeratorCatchFinally: NNEnumeratorBase
+        {
+            private GraphNode gn;
+            private int index = 0;
+            private System.Collections.Generic.IEnumerator<GraphNode> realEnumerator;
+            public NNEnumeratorCatchFinally(GraphNode gn)
+            {
+                this.gn = gn;
+                this.realEnumerator = gn.nextNodes.GetEnumerator();
+            }
+            public override bool MoveNext()
+            {
+                /*
+                 * First off, return any targets the instruction can come up with.
+                 */
+                if(realEnumerator.MoveNext())
+                {
+                    nn = realEnumerator.Current;
+                    return true;
+                }
+
+                /*
+                 * Then if this instruction is in a try section, say this instruction 
+                 * can potentially branch to the beginning of the corresponding 
+                 * catch/finally.
+                 */
+                if((index == 0) && (gn.tryBlock != null))
+                {
+                    index++;
+                    nn = gn.tryBlock.catchFinallyBlock;
+                    return true;
+                }
+
+                /*
+                 * That's all we can do.
+                 */
+                nn = null;
+                return false;
+            }
+            public override void Reset()
+            {
+                realEnumerator.Reset();
+                index = 0;
+                nn = null;
+            }
+        }
+
+        /**
+         * @brief This default iterator always returns the next inline node as the one-and-only next node.
+         *        Other instructions need to override it if they can possibly do other than that.
+         */
+
+        /**
+         * @brief GetNNEnumerable() gets the nextnode enumerable part of a GraphNode,
+         *        which in turn gives the list of nodes that can possibly be next in 
+         *        a flow-control sense.  It simply instantiates the NNEnumerator sub-
+         *        class which does the actual enumeration.
+         */
+        protected virtual System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNode gn;
+            private int index;
+            public NNEnumerator(GraphNode gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                switch(index)
+                {
+                    case 0:
+                        {
+                            index++;
+                            nn = gn.nextLin;
+                            return nn != null;
+                        }
+                    case 1:
+                        {
+                            nn = null;
+                            return false;
+                        }
+                }
+                throw new Exception();
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    /**
+     * @brief Things that derive from this are the beginning of a block.
+     *        A block of code is that which begins with a label or is the beginning of all code
+     *        and it contains no labels, ie, it can't be jumped into other than at its beginning.
+     */
+    public abstract class GraphNodeBlock: GraphNode
+    {
+        public List<ScriptMyLocal> localsWrittenBeforeRead = new List<ScriptMyLocal>();
+        public List<ScriptMyLocal> localsReadBeforeWritten = new List<ScriptMyLocal>();
+        public int hasBeenResolved;
+        public GraphNodeBlock(ScriptCollector coll) : base(coll) { }
+    }
+
+    /**
+     * @brief This placeholder is at the beginning of the code so the first few instructions 
+     *        belong to some block.
+     */
+    public class GraphNodeBegin: GraphNodeBlock
+    {
+        public GraphNodeBegin(ScriptCollector coll) : base(coll) { }
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("begin");
+        }
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+        }
+    }
+
+    /**
+     * @brief Beginning of try block.
+     */
+    public class GraphNodeBeginExceptionBlock: GraphNodeBlock
+    {
+        public GraphNodeBeginExceptionBlock outerTryBlock;      // next outer try opcode or null
+        public GraphNodeCatchFinallyBlock catchFinallyBlock;  // start of associated catch or finally
+        public GraphNodeEndExceptionBlock endExcBlock;        // end of associated catch or finally
+        public int excBlkSeqNo;                                 // debugging
+
+        public GraphNodeBeginExceptionBlock(ScriptCollector coll) : base(coll)
+        {
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // we should always start try blocks with nothing on stack
+            // ...as CLI wipes stack for various conditions
+            if(coll.stackDepth.Count != 0)
+            {
+                throw new Exception("stack depth " + coll.stackDepth.Count);
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("  beginexceptionblock_");
+            sb.Append(excBlkSeqNo);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.BeginExceptionBlock();
+        }
+    }
+
+    /**
+     * @brief Beginning of catch or finally block.
+     */
+    public abstract class GraphNodeCatchFinallyBlock: GraphNodeBlock
+    {
+        public GraphNodeCatchFinallyBlock(ScriptCollector coll) : base(coll)
+        {
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // we should always start catch/finally blocks with nothing on stack
+            // ...as CLI wipes stack for various conditions
+            if(coll.stackDepth.Count != 0)
+            {
+                throw new Exception("stack depth " + coll.stackDepth.Count);
+            }
+        }
+    }
+
+    /**
+     * @brief Beginning of catch block.
+     */
+    public class GraphNodeBeginCatchBlock: GraphNodeCatchFinallyBlock
+    {
+        public Type excType;
+
+        public GraphNodeBeginCatchBlock(ScriptCollector coll, Type excType) : base(coll)
+        {
+            this.excType = excType;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // catch block always enters with one value on stack
+            if(coll.stackDepth.Count != 0)
+            {
+                throw new Exception("stack depth " + coll.stackDepth.Count);
+            }
+            coll.stackDepth.Push(excType);
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("  begincatchblock_");
+            sb.Append(excBlock.excBlkSeqNo);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.BeginCatchBlock(excType);
+        }
+
+        /**
+         * @brief The beginning of every catch { } conditinally branches to the beginning 
+         *        of all outer catch { }s up to and including the next outer finally { }.
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeBeginCatchBlock gn;
+            private int index;
+            public NNEnumerator(GraphNodeBeginCatchBlock gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                while(true)
+                {
+                    switch(index)
+                    {
+                        case 0:
+                            {
+                                // start with the fallthru
+                                nn = gn.nextLin;
+                                index++;
+                                return true;
+                            }
+
+                        case 1:
+                            {
+                                // get the first outer catch { } or finally { }
+                                // pretend we last returned beginning of this catch { }
+                                // then loop back to get next outer catch { } or finally { }
+                                nn = gn;
+                                break;
+                            }
+
+                        case 2:
+                            {
+                                // nn points to a catch { } previously returned
+                                // get the corresponding try { }
+                                GraphNodeBeginExceptionBlock nntry = nn.excBlock;
+
+                                // step out to next outer try { }
+                                nntry = nntry.excBlock;
+                                if(nntry == null)
+                                    break;
+
+                                // return corresponding catch { } or finally { }
+                                nn = nntry.catchFinallyBlock;
+
+                                // if it's a finally { } we don't do anything after that
+                                if(nn is GraphNodeBeginFinallyBlock)
+                                    index++;
+                                return true;
+                            }
+
+                        case 3:
+                            {
+                                // we've returned the fallthru, catches and one finally
+                                // so there's nothing more to say
+                                nn = null;
+                                return false;
+                            }
+
+                        default:
+                            throw new Exception();
+                    }
+                    index++;
+                }
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    /**
+     * @brief Beginning of finally block.
+     */
+    public class GraphNodeBeginFinallyBlock: GraphNodeCatchFinallyBlock
+    {
+
+        // leaveTargets has a list of all the targets of any contained 
+        // leave instructions, ie, where an endfinally can possibly jump.
+        // But only those targets within the next outer finally { }, we 
+        // don't contain any targets outside of that, those targets are 
+        // stored in the actual finally that will jump to the target.
+        // The endfinally enumerator assumes that it is always possible 
+        // for it to jump to the next outer finally (as would happen for
+        // an uncaught exception), so no need to do anything special.
+        public List<GraphNodeBlock> leaveTargets = new List<GraphNodeBlock>();
+
+        public GraphNodeBeginFinallyBlock(ScriptCollector coll) : base(coll)
+        {
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("  beginfinallyblock_");
+            sb.Append(excBlock.excBlkSeqNo);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.BeginFinallyBlock();
+        }
+    }
+
+    /**
+     * @brief End of try/catch/finally block.
+     */
+    public class GraphNodeEndExceptionBlock: GraphNode
+    {
+        public GraphNodeEndExceptionBlock(ScriptCollector coll) : base(coll)
+        {
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // we should always end exception blocks with nothing on stack
+            // ...as CLI wipes stack for various conditions
+            if(coll.stackDepth.Count != 0)
+            {
+                throw new Exception("stack depth " + coll.stackDepth.Count);
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("  endexceptionblock_");
+            sb.Append(excBlock.excBlkSeqNo);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.EndExceptionBlock();
+        }
+    }
+
+    /**
+     * @brief Actual instruction emits...
+     */
+    public abstract class GraphNodeEmit: GraphNode
+    {
+        public OpCode opcode;
+        public Token errorAt;
+
+        public GraphNodeEmit(ScriptCollector coll, Token errorAt, OpCode opcode) : base(coll)
+        {
+            this.opcode = opcode;
+            this.errorAt = errorAt;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // compute resultant stack depth
+            int stack = coll.stackDepth.Count;
+
+            if((stack != 0) && ((opcode == OpCodes.Endfinally) || (opcode == OpCodes.Leave) || (opcode == OpCodes.Rethrow)))
+            {
+                throw new Exception(opcode + " stack depth " + stack);
+            }
+            if((stack != 1) && (opcode == OpCodes.Throw))
+            {
+                throw new Exception(opcode + " stack depth " + stack);
+            }
+        }
+
+        /**
+         * @brief See if it's possible for it to fall through to the next inline (nextLin) instruction.
+         */
+        public override bool CanFallThrough()
+        {
+            switch(opcode.FlowControl)
+            {
+                case FlowControl.Branch:
+                    return false;  // unconditional branch
+                case FlowControl.Break:
+                    return true;   // break
+                case FlowControl.Call:
+                    return true;   // call
+                case FlowControl.Cond_Branch:
+                    return true;   // conditional branch
+                case FlowControl.Next:
+                    return true;   // falls through to next instruction
+                case FlowControl.Return:
+                    return false;  // return
+                case FlowControl.Throw:
+                    return false;  // throw
+                default:
+                    {
+                        string op = opcode.ToString();
+                        if(op == "volatile.")
+                            return true;
+                        throw new Exception("unknown flow control " + opcode.FlowControl + " for " + op);
+                    }
+            }
+        }
+
+        // if followed by OpCodes.Pop, it can be discarded
+        public bool isPoppable
+        {
+            get
+            {
+                return
+                    ((opcode.StackBehaviourPop == StackBehaviour.Pop0) &&    // ldarg,ldloc,ldsfld
+                     (opcode.StackBehaviourPush == StackBehaviour.Push1)) ||
+                    ((opcode.StackBehaviourPop == StackBehaviour.Pop0) &&    // ldarga,ldloca,ldc,ldsflda,...
+                     (opcode.StackBehaviourPush == StackBehaviour.Pushi)) ||
+                    (opcode == OpCodes.Ldnull) ||
+                    (opcode == OpCodes.Ldc_R4) ||
+                    (opcode == OpCodes.Ldc_R8) ||
+                    (opcode == OpCodes.Ldstr) ||
+                    (opcode == OpCodes.Ldc_I8) ||
+                    (opcode == OpCodes.Dup);
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append("".PadRight(OPINDENT));
+            sb.Append(opcode.ToString().PadRight(OPDEBLEN));
+        }
+
+        /**
+         * @brief If instruction is terminating, we say there is nothing following (eg, return).
+         *        Otherwise, say the one-and-only next instruction is the next instruction inline.
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeEmit gn;
+            private int index;
+            public NNEnumerator(GraphNodeEmit gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                switch(index)
+                {
+                    case 0:
+                        {
+                            if(gn.CanFallThrough())
+                            {
+                                index++;
+                                nn = gn.nextLin;
+                                return nn != null;
+                            }
+                            return false;
+                        }
+                    case 1:
+                        {
+                            nn = null;
+                            return false;
+                        }
+                }
+                throw new Exception();
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    public class GraphNodeEmitNull: GraphNodeEmit
+    {
+        public GraphNodeEmitNull(ScriptCollector coll, Token errorAt, OpCode opcode) : base(coll, errorAt, opcode)
+        {
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "nop":
+                    break;
+                case "break":
+                    break;
+                case "volatile.":
+                    break;
+                case "ldarg.0":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[0]);
+                    break;
+                case "ldarg.1":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[1]);
+                    break;
+                case "ldarg.2":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[2]);
+                    break;
+                case "ldarg.3":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[3]);
+                    break;
+                case "ldnull":
+                    coll.stackDepth.Push(null);
+                    break;
+                case "ldc.i4.m1":
+                case "ldc.i4.0":
+                case "ldc.i4.1":
+                case "ldc.i4.2":
+                case "ldc.i4.3":
+                case "ldc.i4.4":
+                case "ldc.i4.5":
+                case "ldc.i4.6":
+                case "ldc.i4.7":
+                case "ldc.i4.8":
+                    {
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "dup":
+                    {
+                        Type t = coll.stackDepth.Peek(0);
+                        bool b = coll.stackDepth.PeekBoxed(0);
+                        coll.stackDepth.Push(t, b);
+                        break;
+                    }
+                case "pop":
+                    {
+                        coll.stackDepth.Pop(1);
+                        break;
+                    }
+                case "ret":
+                    {
+                        int sd = (coll.wrapped.retType != typeof(void)) ? 1 : 0;
+                        if(coll.stackDepth.Count != sd)
+                            throw new Exception("bad stack depth");
+                        if(sd > 0)
+                        {
+                            coll.stackDepth.Pop(coll.wrapped.retType);
+                        }
+                        break;
+                    }
+                case "add":
+                case "sub":
+                case "mul":
+                case "div":
+                case "div.un":
+                case "rem":
+                case "rem.un":
+                case "and":
+                case "or":
+                case "xor":
+                case "shl":
+                case "shr":
+                case "shr.un":
+                case "add.ovf":
+                case "add.ovf.un":
+                case "mul.ovf":
+                case "mul.ovf.un":
+                case "sub.ovf":
+                case "sub.ovf.un":
+                    {
+                        coll.stackDepth.PopNumVal();
+                        Type t = coll.stackDepth.PopNumVal();
+                        coll.stackDepth.Push(t);
+                        break;
+                    }
+                case "neg":
+                case "not":
+                    {
+                        Type t = coll.stackDepth.PopNumVal();
+                        coll.stackDepth.Push(t);
+                        break;
+                    }
+                case "conv.i1":
+                case "conv.i2":
+                case "conv.i4":
+                case "conv.i8":
+                case "conv.r4":
+                case "conv.r8":
+                case "conv.u4":
+                case "conv.u8":
+                case "conv.r.un":
+                case "conv.ovf.i1.un":
+                case "conv.ovf.i2.un":
+                case "conv.ovf.i4.un":
+                case "conv.ovf.i8.un":
+                case "conv.ovf.u1.un":
+                case "conv.ovf.u2.un":
+                case "conv.ovf.u4.un":
+                case "conv.ovf.u8.un":
+                case "conv.ovf.i.un":
+                case "conv.ovf.u.un":
+                case "conv.ovf.i1":
+                case "conv.ovf.u1":
+                case "conv.ovf.i2":
+                case "conv.ovf.u2":
+                case "conv.ovf.i4":
+                case "conv.ovf.u4":
+                case "conv.ovf.i8":
+                case "conv.ovf.u8":
+                case "conv.u2":
+                case "conv.u1":
+                case "conv.i":
+                case "conv.ovf.i":
+                case "conv.ovf.u":
+                case "conv.u":
+                    {
+                        coll.stackDepth.PopNumVal();
+                        coll.stackDepth.Push(ConvToType(opcode));
+                        break;
+                    }
+                case "throw":
+                    {
+                        if(coll.stackDepth.Count != 1)
+                            throw new Exception("bad stack depth " + coll.stackDepth.Count);
+                        coll.stackDepth.PopRef();
+                        break;
+                    }
+                case "ldlen":
+                    {
+                        coll.stackDepth.Pop(typeof(string));
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "ldelem.i1":
+                case "ldelem.u1":
+                case "ldelem.i2":
+                case "ldelem.u2":
+                case "ldelem.i4":
+                case "ldelem.u4":
+                case "ldelem.i8":
+                case "ldelem.i":
+                case "ldelem.r4":
+                case "ldelem.r8":
+                case "ldelem.ref":
+                    {
+                        Type t = coll.stackDepth.Peek(1).GetElementType();
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(t.MakeArrayType());
+                        coll.stackDepth.Push(t);
+                        break;
+                    }
+                case "stelem.i":
+                case "stelem.i1":
+                case "stelem.i2":
+                case "stelem.i4":
+                case "stelem.i8":
+                case "stelem.r4":
+                case "stelem.r8":
+                case "stelem.ref":
+                    {
+                        Type t = coll.stackDepth.Peek(2).GetElementType();
+                        coll.stackDepth.Pop(t);
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(t.MakeArrayType());
+                        break;
+                    }
+                case "endfinally":
+                case "rethrow":
+                    {
+                        if(coll.stackDepth.Count != 0)
+                            throw new Exception("bad stack depth " + coll.stackDepth.Count);
+                        break;
+                    }
+                case "ceq":
+                    {
+                        Type t = coll.stackDepth.Pop(1);
+                        if(t == null)
+                        {
+                            coll.stackDepth.PopRef();
+                        }
+                        else
+                        {
+                            coll.stackDepth.Pop(t);
+                        }
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "cgt":
+                case "cgt.un":
+                case "clt":
+                case "clt.un":
+                    {
+                        coll.stackDepth.PopNumVal();
+                        coll.stackDepth.PopNumVal();
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "ldind.i4":
+                    {
+                        coll.stackDepth.Pop(typeof(int).MakeByRefType());
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "stind.i4":
+                    {
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(typeof(int).MakeByRefType());
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        private static Type ConvToType(OpCode opcode)
+        {
+            string s = opcode.ToString();
+            s = s.Substring(5);  // strip off "conv."
+            if(s.StartsWith("ovf."))
+                s = s.Substring(4);
+            if(s.EndsWith(".un"))
+                s = s.Substring(0, s.Length - 3);
+
+            switch(s)
+            {
+                case "i":
+                    return typeof(IntPtr);
+                case "i1":
+                    return typeof(sbyte);
+                case "i2":
+                    return typeof(short);
+                case "i4":
+                    return typeof(int);
+                case "i8":
+                    return typeof(long);
+                case "r":
+                case "r4":
+                    return typeof(float);
+                case "r8":
+                    return typeof(double);
+                case "u1":
+                    return typeof(byte);
+                case "u2":
+                    return typeof(ushort);
+                case "u4":
+                    return typeof(uint);
+                case "u8":
+                    return typeof(ulong);
+                case "u":
+                    return typeof(UIntPtr);
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode);
+        }
+    }
+
+    public class GraphNodeEmitNullEndfinally: GraphNodeEmitNull
+    {
+        public GraphNodeEmitNullEndfinally(ScriptCollector coll, Token errorAt) : base(coll, errorAt, OpCodes.Endfinally)
+        {
+        }
+
+        /**
+         * @brief Endfinally can branch to:
+         *          1) the corresponding EndExceptionBlock
+         *          2) any of the corresponding BeginFinallyBlock's leaveTargets
+         *          3) the next outer BeginFinallyBlock
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeEmitNullEndfinally gn;
+            private IEnumerator<GraphNodeBlock> leaveTargetEnumerator;
+            private int index;
+            public NNEnumerator(GraphNodeEmitNullEndfinally gn)
+            {
+                this.gn = gn;
+
+                // endfinally instruction must be within some try/catch/finally mess
+                GraphNodeBeginExceptionBlock thistry = gn.excBlock;
+
+                // endfinally instruction must be within some finally { } mess
+                GraphNodeBeginFinallyBlock thisfin = (GraphNodeBeginFinallyBlock)thistry.catchFinallyBlock;
+
+                // get the list of the finally { } leave instruction targets
+                this.leaveTargetEnumerator = thisfin.leaveTargets.GetEnumerator();
+            }
+            public override bool MoveNext()
+            {
+                while(true)
+                {
+                    switch(index)
+                    {
+
+                        // to start, return end of our finally { }
+                        case 0:
+                            {
+                                GraphNodeBeginExceptionBlock thistry = gn.excBlock;
+                                nn = thistry.endExcBlock;
+                                if(nn == null)
+                                    throw new NullReferenceException("thistry.endExcBlock");
+                                index++;
+                                return true;
+                            }
+
+                        // return next one of our finally { }'s leave targets
+                        // ie, where any leave instructions in the try { } want 
+                        // the finally { } to go to when it finishes
+                        case 1:
+                            {
+                                if(this.leaveTargetEnumerator.MoveNext())
+                                {
+                                    nn = this.leaveTargetEnumerator.Current;
+                                    if(nn == null)
+                                        throw new NullReferenceException("this.leaveTargetEnumerator.Current");
+                                    return true;
+                                }
+                                break;
+                            }
+
+                        // return beginning of next outer finally { }
+                        case 2:
+                            {
+                                GraphNodeBeginExceptionBlock nntry = gn.excBlock;
+                                while((nntry = nntry.excBlock) != null)
+                                {
+                                    if(nntry.catchFinallyBlock is GraphNodeBeginFinallyBlock)
+                                    {
+                                        nn = nntry.catchFinallyBlock;
+                                        if(nn == null)
+                                            throw new NullReferenceException("nntry.catchFinallyBlock");
+                                        index++;
+                                        return true;
+                                    }
+                                }
+                                break;
+                            }
+
+                        // got nothing more
+                        case 3:
+                            {
+                                return false;
+                            }
+
+                        default:
+                            throw new Exception();
+                    }
+                    index++;
+                }
+            }
+            public override void Reset()
+            {
+                leaveTargetEnumerator.Reset();
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    public class GraphNodeEmitField: GraphNodeEmit
+    {
+        public FieldInfo field;
+
+        public GraphNodeEmitField(ScriptCollector coll, Token errorAt, OpCode opcode, FieldInfo field) : base(coll, errorAt, opcode)
+        {
+            this.field = field;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldfld":
+                    PopPointer();
+                    coll.stackDepth.Push(field.FieldType);
+                    break;
+                case "ldflda":
+                    PopPointer();
+                    coll.stackDepth.Push(field.FieldType.MakeByRefType());
+                    break;
+                case "stfld":
+                    coll.stackDepth.Pop(field.FieldType);
+                    PopPointer();
+                    break;
+                case "ldsfld":
+                    coll.stackDepth.Push(field.FieldType);
+                    break;
+                case "ldsflda":
+                    coll.stackDepth.Push(field.FieldType.MakeByRefType());
+                    break;
+                case "stsfld":
+                    coll.stackDepth.Pop(field.FieldType);
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+        private void PopPointer()
+        {
+            Type t = field.DeclaringType;               // get class/field type
+            if(t.IsValueType)
+            {
+                Type brt = t.MakeByRefType();      // if value type, eg Vector, it can be pushed by reference or by value
+                int c = coll.stackDepth.Count;
+                if((c > 0) && (coll.stackDepth[c - 1] == brt))
+                    t = brt;
+            }
+            coll.stackDepth.Pop(t);                    // type of what should be on the stack pointing to object or struct
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(field.Name);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, field);
+        }
+    }
+
+    public class GraphNodeEmitLocal: GraphNodeEmit
+    {
+        public ScriptMyLocal myLocal;
+
+        public GraphNodeEmitLocal(ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLocal myLocal) : base(coll, errorAt, opcode)
+        {
+            this.myLocal = myLocal;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldloc":
+                    coll.stackDepth.Push(myLocal.type);
+                    break;
+                case "ldloca":
+                    coll.stackDepth.Push(myLocal.type.MakeByRefType());
+                    break;
+                case "stloc":
+                    coll.stackDepth.Pop(myLocal.type);
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(myLocal.name);
+        }
+
+        public override ScriptMyLocal ReadsLocal()
+        {
+            if(opcode == OpCodes.Ldloc)
+                return myLocal;
+            if(opcode == OpCodes.Ldloca)
+                return myLocal;
+            if(opcode == OpCodes.Stloc)
+                return null;
+            throw new Exception("unknown opcode " + opcode);
+        }
+        public override ScriptMyLocal WritesLocal()
+        {
+            if(opcode == OpCodes.Ldloc)
+                return null;
+            if(opcode == OpCodes.Ldloca)
+                return myLocal;
+            if(opcode == OpCodes.Stloc)
+                return myLocal;
+            throw new Exception("unknown opcode " + opcode);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, myLocal);
+        }
+    }
+
+    public class GraphNodeEmitType: GraphNodeEmit
+    {
+        public Type type;
+
+        public GraphNodeEmitType(ScriptCollector coll, Token errorAt, OpCode opcode, Type type) : base(coll, errorAt, opcode)
+        {
+            this.type = type;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "castclass":
+                case "isinst":
+                    {
+                        coll.stackDepth.PopRef();
+                        coll.stackDepth.Push(type, type.IsValueType);
+                        break;
+                    }
+                case "box":
+                    {
+                        if(!type.IsValueType)
+                            throw new Exception("can't box a non-value type");
+                        coll.stackDepth.Pop(type);
+                        coll.stackDepth.Push(type, true);
+                        break;
+                    }
+                case "unbox":
+                case "unbox.any":
+                    {
+                        if(!type.IsValueType)
+                            throw new Exception("can't unbox to a non-value type");
+                        coll.stackDepth.PopRef();
+                        coll.stackDepth.Push(type);
+                        break;
+                    }
+                case "newarr":
+                    {
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Push(type.MakeArrayType());
+                        break;
+                    }
+                case "sizeof":
+                    {
+                        coll.stackDepth.Pop(1);
+                        coll.stackDepth.Push(typeof(int));
+                        break;
+                    }
+                case "ldelem":
+                    {
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(type.MakeArrayType());
+                        coll.stackDepth.Push(type);
+                        break;
+                    }
+                case "ldelema":
+                    {
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(type.MakeArrayType());
+                        coll.stackDepth.Push(type.MakeByRefType());
+                        break;
+                    }
+                case "stelem":
+                    {
+                        coll.stackDepth.Pop(type);
+                        coll.stackDepth.Pop(typeof(int));
+                        coll.stackDepth.Pop(type.MakeArrayType());
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(type.Name);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, type);
+        }
+    }
+
+    public class GraphNodeEmitLabel: GraphNodeEmit
+    {
+        public ScriptMyLabel myLabel;
+
+        public GraphNodeEmitLabel(ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLabel myLabel) : base(coll, errorAt, opcode)
+        {
+            this.myLabel = myLabel;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "brfalse.s":
+                case "brtrue.s":
+                case "brfalse":
+                case "brtrue":
+                    {
+                        coll.stackDepth.Pop(1);
+                        break;
+                    }
+                case "beq.s":
+                case "bge.s":
+                case "bgt.s":
+                case "ble.s":
+                case "blt.s":
+                case "bne.un.s":
+                case "bge.un.s":
+                case "bgt.un.s":
+                case "ble.un.s":
+                case "blt.un.s":
+                case "beq":
+                case "bge":
+                case "bgt":
+                case "ble":
+                case "blt":
+                case "bne.un":
+                case "bge.un":
+                case "bgt.un":
+                case "ble.un":
+                case "blt.un":
+                    {
+                        coll.stackDepth.PopNumVal();
+                        coll.stackDepth.PopNumVal();
+                        break;
+                    }
+                case "br":
+                case "br.s":
+                    break;
+                case "leave":
+                    {
+                        if(coll.stackDepth.Count != 0)
+                            throw new Exception("bad stack depth " + coll.stackDepth.Count);
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+
+            // if a target doesn't have a depth yet, set its depth to the depth after instruction executes
+            // otherwise, make sure it matches all other branches to that target and what fell through to it
+            coll.stackDepth.Matches(myLabel);
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(myLabel.name);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, myLabel);
+        }
+
+        /**
+         * @brief Conditional branches return the next inline followed by the branch target
+         *        Unconditional branches return only the branch target
+         *        But if the target is outside our scope (eg __retlbl), omit it from the list
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeEmitLabel gn;
+            private int index;
+            public NNEnumerator(GraphNodeEmitLabel gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                switch(gn.opcode.FlowControl)
+                {
+                    case FlowControl.Branch:
+                        {
+                            // unconditional branch just goes to target and nothing else
+                            switch(index)
+                            {
+                                case 0:
+                                    {
+                                        nn = gn.myLabel.whereAmI;
+                                        index++;
+                                        return nn != null;
+                                    }
+                                case 1:
+                                    {
+                                        return false;
+                                    }
+                            }
+                            throw new Exception();
+                        }
+                    case FlowControl.Cond_Branch:
+                        {
+                            // conditional branch goes inline and to target
+                            switch(index)
+                            {
+                                case 0:
+                                    {
+                                        nn = gn.nextLin;
+                                        index++;
+                                        return true;
+                                    }
+                                case 1:
+                                    {
+                                        nn = gn.myLabel.whereAmI;
+                                        index++;
+                                        return nn != null;
+                                    }
+                                case 2:
+                                    {
+                                        return false;
+                                    }
+                            }
+                            throw new Exception();
+                        }
+                    default:
+                        throw new Exception("unknown flow control " + gn.opcode.FlowControl.ToString() +
+                                             " of " + gn.opcode.ToString());
+                }
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    public class GraphNodeEmitLabelLeave: GraphNodeEmitLabel
+    {
+        public GraphNodeBlock unwindTo;  // if unwinding, innermost finally block being unwound
+                                         //         else, same as myTarget.whereAmI
+                                         // null if unwinding completely out of scope, eg, __retlbl
+
+        public GraphNodeEmitLabelLeave(ScriptCollector coll, Token errorAt, ScriptMyLabel myLabel) : base(coll, errorAt, OpCodes.Leave, myLabel)
+        {
+        }
+
+        /**
+         * @brief Leave instructions have exactly one unconditional next node.
+         *        Either the given target if within the same try block 
+         *        or the beginning of the intervening finally block.
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeEmitLabelLeave gn;
+            private int index;
+            public NNEnumerator(GraphNodeEmitLabelLeave gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                if(index == 0)
+                {
+                    nn = gn.unwindTo;
+                    index++;
+                    return nn != null;
+                }
+                nn = null;
+                return false;
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    public class GraphNodeEmitLabels: GraphNodeEmit
+    {
+        public ScriptMyLabel[] myLabels;
+
+        public GraphNodeEmitLabels(ScriptCollector coll, Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels) : base(coll, errorAt, opcode)
+        {
+            this.myLabels = myLabels;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "switch":
+                    {
+                        coll.stackDepth.Pop(typeof(int));
+                        break;
+                    }
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+
+            // if a target doesn't have a depth yet, set its depth to the depth after instruction executes
+            // otherwise, make sure it matches all other branches to that target and what fell through to it
+            foreach(ScriptMyLabel myLabel in myLabels)
+            {
+                coll.stackDepth.Matches(myLabel);
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            bool first = true;
+            foreach(ScriptMyLabel lbl in myLabels)
+            {
+                if(!first)
+                    sb.Append(',');
+                sb.Append(lbl.name);
+                first = false;
+            }
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, myLabels);
+        }
+
+        /**
+         * @brief Return list of all labels followed by the next linear instruction
+         *        But if the target is outside our scope (eg __retlbl), omit it from the list
+         */
+        protected override System.Collections.Generic.IEnumerable<GraphNode> GetNNEnumerable()
+        {
+            return new NNEnumerable(this, typeof(NNEnumerator));
+        }
+
+        private class NNEnumerator: NNEnumeratorBase
+        {
+            private GraphNodeEmitLabels gn;
+            private int index;
+            public NNEnumerator(GraphNodeEmitLabels gn)
+            {
+                this.gn = gn;
+            }
+            public override bool MoveNext()
+            {
+                /*
+                 * Return next from list of switch case labels.
+                 */
+                while(index < gn.myLabels.Length)
+                {
+                    nn = gn.myLabels[index++].whereAmI;
+                    if(nn != null)
+                        return true;
+                }
+
+                /*
+                 * If all ran out, the switch instruction falls through.
+                 */
+                if(index == gn.myLabels.Length)
+                {
+                    index++;
+                    nn = gn.nextLin;
+                    return true;
+                }
+
+                /*
+                 * Even ran out of that, say there's nothing more.
+                 */
+                nn = null;
+                return false;
+            }
+            public override void Reset()
+            {
+                index = 0;
+                nn = null;
+            }
+        }
+    }
+
+    public class GraphNodeEmitIntMeth: GraphNodeEmit
+    {
+        public ScriptObjWriter method;
+
+        public GraphNodeEmitIntMeth(ScriptCollector coll, Token errorAt, OpCode opcode, ScriptObjWriter method) : base(coll, errorAt, opcode)
+        {
+            this.method = method;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "call":
+                    {
+
+                        // calls have Varpop so pop the number of arguments
+                        // they are all static so there is no separate 'this' parameter
+                        coll.stackDepth.Pop(this.method.argTypes);
+
+                        // calls are also Varpush so they push a return value iff non-void
+                        if(this.method.retType != typeof(void))
+                            coll.stackDepth.Push(this.method.retType);
+                        break;
+                    }
+
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(method.methName);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, method);
+        }
+    }
+
+    public class GraphNodeEmitExtMeth: GraphNodeEmit
+    {
+        public MethodInfo method;
+
+        public GraphNodeEmitExtMeth(ScriptCollector coll, Token errorAt, OpCode opcode, MethodInfo method) : base(coll, errorAt, opcode)
+        {
+            this.method = method;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "call":
+                case "callvirt":
+                    {
+
+                        // calls have Varpop so pop the number of arguments
+                        coll.stackDepth.Pop(this.method.GetParameters());
+                        if((this.method.CallingConvention & CallingConventions.HasThis) != 0)
+                        {
+                            coll.stackDepth.Pop(method.DeclaringType);
+                        }
+
+                        // calls are also Varpush so they push a return value iff non-void
+                        if(this.method.ReturnType != typeof(void))
+                            coll.stackDepth.Push(this.method.ReturnType);
+                        break;
+                    }
+
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(method.Name);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, method);
+        }
+    }
+
+    public class GraphNodeEmitCtor: GraphNodeEmit
+    {
+        public ConstructorInfo ctor;
+
+        public GraphNodeEmitCtor(ScriptCollector coll, Token errorAt, OpCode opcode, ConstructorInfo ctor) : base(coll, errorAt, opcode)
+        {
+            this.ctor = ctor;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "newobj":
+                    {
+                        coll.stackDepth.Pop(ctor.GetParameters());
+                        coll.stackDepth.Push(ctor.DeclaringType);
+                        break;
+                    }
+
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(ctor.ReflectedType.Name);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, ctor);
+        }
+    }
+
+    public class GraphNodeEmitDouble: GraphNodeEmit
+    {
+        public double value;
+
+        public GraphNodeEmitDouble(ScriptCollector coll, Token errorAt, OpCode opcode, double value) : base(coll, errorAt, opcode)
+        {
+            this.value = value;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldc.r8":
+                    coll.stackDepth.Push(typeof(double));
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(value);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, value);
+        }
+    }
+
+    public class GraphNodeEmitFloat: GraphNodeEmit
+    {
+        public float value;
+
+        public GraphNodeEmitFloat(ScriptCollector coll, Token errorAt, OpCode opcode, float value) : base(coll, errorAt, opcode)
+        {
+            this.value = value;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldc.r4":
+                    coll.stackDepth.Push(typeof(float));
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(value);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, value);
+        }
+    }
+
+    public class GraphNodeEmitInt: GraphNodeEmit
+    {
+        public int value;
+
+        public GraphNodeEmitInt(ScriptCollector coll, Token errorAt, OpCode opcode, int value) : base(coll, errorAt, opcode)
+        {
+            this.value = value;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldarg":
+                case "ldarg.s":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[value]);
+                    break;
+                case "ldarga":
+                case "ldarga.s":
+                    coll.stackDepth.Push(coll.wrapped.argTypes[value].MakeByRefType());
+                    break;
+                case "starg":
+                case "starg.s":
+                    coll.stackDepth.Pop(coll.wrapped.argTypes[value]);
+                    break;
+                case "ldc.i4":
+                case "ldc.i4.s":
+                    coll.stackDepth.Push(typeof(int));
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append(value);
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, value);
+        }
+    }
+
+    public class GraphNodeEmitString: GraphNodeEmit
+    {
+        public string value;
+
+        public GraphNodeEmitString(ScriptCollector coll, Token errorAt, OpCode opcode, string value) : base(coll, errorAt, opcode)
+        {
+            this.value = value;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            switch(opcode.ToString())
+            {
+                case "ldstr":
+                    coll.stackDepth.Push(typeof(string));
+                    break;
+                default:
+                    throw new Exception("unknown opcode " + opcode.ToString());
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            base.DebString(sb);
+            sb.Append("\"");
+            sb.Append(value);
+            sb.Append("\"");
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.Emit(errorAt, opcode, value);
+        }
+    }
+
+    public class GraphNodeMarkLabel: GraphNodeBlock
+    {
+        public ScriptMyLabel myLabel;
+
+        public GraphNodeMarkLabel(ScriptCollector coll, ScriptMyLabel myLabel) : base(coll)
+        {
+            this.myLabel = myLabel;
+        }
+
+        public override void ChainLin()
+        {
+            base.ChainLin();
+
+            // if previous instruction can fall through to this label,
+            //     if the label doesn't yet have a stack depth, mark it with current stack depth
+            //     else, the label's stack depth from forward branches and current stack depth must match
+            // else,
+            //     label must have had a forward branch to it so we can know stack depth
+            //     set the current stack depth to the label's stack depth as of that forward branch
+            if(myLabel.whereAmI.prevLin.CanFallThrough())
+            {
+                coll.stackDepth.Matches(myLabel);
+            }
+            else
+            {
+                if(myLabel.stackDepth == null)
+                {
+                    throw new Exception("stack depth unknown at " + myLabel.name);
+                }
+                coll.stackDepth.Clear();
+                int n = myLabel.stackDepth.Length;
+                for(int i = 0; i < n; i++)
+                {
+                    coll.stackDepth.Push(myLabel.stackDepth[i], myLabel.stackBoxeds[i]);
+                }
+            }
+        }
+
+        public override void DebString(StringBuilder sb)
+        {
+            sb.Append(myLabel.name);
+            sb.Append(':');
+            if(myLabel.stackDepth != null)
+            {
+                sb.Append("  [");
+                sb.Append(myLabel.stackDepth.Length);
+                sb.Append(']');
+            }
+        }
+
+        public override void WriteOutOne(ScriptMyILGen ilGen)
+        {
+            ilGen.MarkLabel(myLabel);
+        }
+    }
+
+
+    /**
+     * @brief Generates enumerator that steps through list of nodes that can
+     *        possibly be next in a flow-control sense.
+     */
+    public class NNEnumerable: System.Collections.Generic.IEnumerable<GraphNode>
+    {
+        private object[] cps;
+        private ConstructorInfo ci;
+
+        public NNEnumerable(GraphNode gn, Type nnEnumeratorType)
+        {
+            this.cps = new object[] { gn };
+            this.ci = nnEnumeratorType.GetConstructor(new Type[] { gn.GetType() });
+        }
+        System.Collections.Generic.IEnumerator<GraphNode> System.Collections.Generic.IEnumerable<GraphNode>.GetEnumerator()
+        {
+            return (System.Collections.Generic.IEnumerator<GraphNode>)ci.Invoke(cps);
+        }
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return (System.Collections.IEnumerator)ci.Invoke(cps);
+        }
+    }
+
+
+    /**
+     * @brief Steps through list of nodes that can possible be next in a flow-control sense.
+     */
+    public abstract class NNEnumeratorBase: System.Collections.Generic.IEnumerator<GraphNode>
+    {
+        protected GraphNode nn;
+
+        public abstract bool MoveNext();
+        public abstract void Reset();
+
+        GraphNode System.Collections.Generic.IEnumerator<GraphNode>.Current
+        {
+            get
+            {
+                return this.nn;
+            }
+        }
+        object System.Collections.IEnumerator.Current
+        {
+            get
+            {
+                return this.nn;
+            }
+        }
+        void System.IDisposable.Dispose()
+        {
+        }
+    }
+
+
+    public class ScriptCollector: ScriptMyILGen
+    {
+        public static readonly bool DEBUG = false;
+
+        public ScriptObjWriter wrapped;
+        public GraphNode firstLin, lastLin;
+        private bool resolvedSomething;
+        private int resolveSequence;
+        private int excBlkSeqNos;
+        public StackDepth stackDepth = new StackDepth();
+
+        public GraphNodeBeginExceptionBlock curTryBlock = null;  // pushed at beginning of try
+                                                                 // popped at BEGINNING of catch/finally
+        public GraphNodeBeginExceptionBlock curExcBlock = null;  // pushed at beginning of try
+                                                                 // popped at END of catch/finally
+
+        private List<ScriptMyLocal> declaredLocals = new List<ScriptMyLocal>();
+        private List<ScriptMyLabel> definedLabels = new List<ScriptMyLabel>();
+
+        public string methName
+        {
+            get
+            {
+                return wrapped.methName;
+            }
+        }
+
+        /**
+         * @brief Wrap the optimizer around the ScriptObjWriter to collect the instruction stream.
+         *        All stream-writing calls get saved to our graph nodes instead of being written to object file.
+         */
+        public ScriptCollector(ScriptObjWriter wrapped)
+        {
+            this.wrapped = wrapped;
+            GraphNodeBegin gnb = new GraphNodeBegin(this);
+            this.firstLin = gnb;
+            this.lastLin = gnb;
+        }
+
+        public ScriptMyLocal DeclareLocal(Type type, string name)
+        {
+            ScriptMyLocal loc = new ScriptMyLocal();
+            loc.name = name;
+            loc.type = type;
+            loc.number = wrapped.localNumber++;
+            declaredLocals.Add(loc);
+            return loc;
+        }
+
+        public ScriptMyLabel DefineLabel(string name)
+        {
+            ScriptMyLabel lbl = new ScriptMyLabel();
+            lbl.name = name;
+            lbl.number = wrapped.labelNumber++;
+            definedLabels.Add(lbl);
+            return lbl;
+        }
+
+        public void BeginExceptionBlock()
+        {
+            GraphNodeBeginExceptionBlock tryBlock = new GraphNodeBeginExceptionBlock(this);
+            tryBlock.ChainLin();
+            tryBlock.excBlkSeqNo = ++this.excBlkSeqNos;
+            this.curExcBlock = tryBlock;
+            this.curTryBlock = tryBlock;
+        }
+
+        public void BeginCatchBlock(Type excType)
+        {
+            GraphNodeBeginCatchBlock catchBlock = new GraphNodeBeginCatchBlock(this, excType);
+            catchBlock.ChainLin();
+            if(curExcBlock.catchFinallyBlock != null)
+                throw new Exception("only one catch/finally allowed per try");
+            curExcBlock.catchFinallyBlock = catchBlock;
+            curTryBlock = curExcBlock.tryBlock;
+        }
+
+        public void BeginFinallyBlock()
+        {
+            GraphNodeBeginFinallyBlock finallyBlock = new GraphNodeBeginFinallyBlock(this);
+            finallyBlock.ChainLin();
+            if(curExcBlock.catchFinallyBlock != null)
+                throw new Exception("only one catch/finally allowed per try");
+            curExcBlock.catchFinallyBlock = finallyBlock;
+            curTryBlock = curExcBlock.tryBlock;
+        }
+
+        public void EndExceptionBlock()
+        {
+            GraphNodeEndExceptionBlock endExcBlock = new GraphNodeEndExceptionBlock(this);
+            endExcBlock.ChainLin();
+            curExcBlock.endExcBlock = endExcBlock;
+            curTryBlock = curExcBlock.tryBlock;
+            curExcBlock = curExcBlock.excBlock;
+        }
+
+        public void Emit(Token errorAt, OpCode opcode)
+        {
+            if(opcode == OpCodes.Endfinally)
+            {
+                new GraphNodeEmitNullEndfinally(this, errorAt).ChainLin();
+            }
+            else
+            {
+                new GraphNodeEmitNull(this, errorAt, opcode).ChainLin();
+            }
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, FieldInfo field)
+        {
+            if(field == null)
+                throw new ArgumentNullException("field");
+            new GraphNodeEmitField(this, errorAt, opcode, field).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
+        {
+            new GraphNodeEmitLocal(this, errorAt, opcode, myLocal).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, Type type)
+        {
+            new GraphNodeEmitType(this, errorAt, opcode, type).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
+        {
+            if(opcode == OpCodes.Leave)
+            {
+                new GraphNodeEmitLabelLeave(this, errorAt, myLabel).ChainLin();
+            }
+            else
+            {
+                new GraphNodeEmitLabel(this, errorAt, opcode, myLabel).ChainLin();
+            }
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
+        {
+            new GraphNodeEmitLabels(this, errorAt, opcode, myLabels).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method)
+        {
+            if(method == null)
+                throw new ArgumentNullException("method");
+            new GraphNodeEmitIntMeth(this, errorAt, opcode, method).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, MethodInfo method)
+        {
+            if(method == null)
+                throw new ArgumentNullException("method");
+            new GraphNodeEmitExtMeth(this, errorAt, opcode, method).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor)
+        {
+            if(ctor == null)
+                throw new ArgumentNullException("ctor");
+            new GraphNodeEmitCtor(this, errorAt, opcode, ctor).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, double value)
+        {
+            new GraphNodeEmitDouble(this, errorAt, opcode, value).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, float value)
+        {
+            new GraphNodeEmitFloat(this, errorAt, opcode, value).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, int value)
+        {
+            new GraphNodeEmitInt(this, errorAt, opcode, value).ChainLin();
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, string value)
+        {
+            new GraphNodeEmitString(this, errorAt, opcode, value).ChainLin();
+        }
+
+        public void MarkLabel(ScriptMyLabel myLabel)
+        {
+            myLabel.whereAmI = new GraphNodeMarkLabel(this, myLabel);
+            myLabel.whereAmI.ChainLin();
+        }
+
+        /**
+         * @brief Write the whole graph out to the object file.
+         */
+        public ScriptMyILGen WriteOutAll()
+        {
+            foreach(ScriptMyLocal loc in declaredLocals)
+            {
+                if(loc.isReferenced)
+                    wrapped.DeclareLocal(loc);
+            }
+            foreach(ScriptMyLabel lbl in definedLabels)
+            {
+                wrapped.DefineLabel(lbl);
+            }
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                gn.WriteOutOne(wrapped);
+            }
+            return wrapped;
+        }
+
+        /**
+         * @brief Perform optimizations.
+         */
+        public void Optimize()
+        {
+            if(curExcBlock != null)
+                throw new Exception("exception block still open");
+
+            /*
+             * If an instruction says it doesn't fall through, remove all instructions to
+             * the end of the block.
+             */
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                if(!gn.CanFallThrough())
+                {
+                    GraphNode nn;
+                    while(((nn = gn.nextLin) != null) && !(nn is GraphNodeBlock) &&
+                                              !(nn is GraphNodeEndExceptionBlock))
+                    {
+                        if((gn.nextLin = nn.nextLin) != null)
+                        {
+                            nn.nextLin.prevLin = gn;
+                        }
+                    }
+                }
+            }
+
+            /*
+             * Scan for OpCodes.Leave instructions.
+             * For each found, its target for flow analysis purposes is the beginning of the corresponding
+             * finally block.  And the end of the finally block gets a conditional branch target of the 
+             * leave instruction's target.  A leave instruction can unwind zero or more finally blocks.
+             */
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                if(gn is GraphNodeEmitLabelLeave)
+                {
+                    GraphNodeEmitLabelLeave leaveInstr = (GraphNodeEmitLabelLeave)gn;         // the leave instruction
+                    GraphNodeMarkLabel leaveTarget = leaveInstr.myLabel.whereAmI;             // label being targeted by leave
+                    GraphNodeBeginExceptionBlock leaveTargetsTryBlock =                       // try block directly enclosing leave target
+                        (leaveTarget == null) ? null : leaveTarget.tryBlock;              // ...it must not be unwound
+
+                    /*
+                     * Step through try { }s from the leave instruction towards its target looking for try { }s with finally { }s.
+                     * The leave instruction unconditionally branches to the beginning of the innermost one found.
+                     * The end of the last one found conditionally branches to the leave instruction's target.
+                     * If none found, the leave is a simple unconditional branch to its target.
+                     */
+                    GraphNodeBeginFinallyBlock innerFinallyBlock = null;
+                    for(GraphNodeBeginExceptionBlock tryBlock = leaveInstr.tryBlock;
+                         tryBlock != leaveTargetsTryBlock;
+                         tryBlock = tryBlock.tryBlock)
+                    {
+                        if(tryBlock == null)
+                            throw new Exception("leave target not at or outer to leave instruction");
+                        GraphNodeCatchFinallyBlock cfb = tryBlock.catchFinallyBlock;
+                        if(cfb is GraphNodeBeginFinallyBlock)
+                        {
+                            if(innerFinallyBlock == null)
+                            {
+                                leaveInstr.unwindTo = cfb;
+                            }
+                            innerFinallyBlock = (GraphNodeBeginFinallyBlock)cfb;
+                        }
+                    }
+
+                    /*
+                     * The end of the outermost finally being unwound can conditionally jump to the target of the leave instruction.
+                     * In the case of no finallies being unwound, the leave is just a simple unconditional branch.
+                     */
+                    if(innerFinallyBlock == null)
+                    {
+                        leaveInstr.unwindTo = leaveTarget;
+                    }
+                    else if(!innerFinallyBlock.leaveTargets.Contains(leaveTarget))
+                    {
+                        innerFinallyBlock.leaveTargets.Add(leaveTarget);
+                    }
+                }
+            }
+
+            /*
+             * See which variables a particular block reads before writing.
+             * This just considers the block itself and nothing that it branches to or fallsthru to.
+             */
+            GraphNodeBlock currentBlock = null;
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                if(gn is GraphNodeBlock)
+                    currentBlock = (GraphNodeBlock)gn;
+                ScriptMyLocal rdlcl = gn.ReadsLocal();
+                if((rdlcl != null) &&
+                    !currentBlock.localsWrittenBeforeRead.Contains(rdlcl) &&
+                    !currentBlock.localsReadBeforeWritten.Contains(rdlcl))
+                {
+                    currentBlock.localsReadBeforeWritten.Add(rdlcl);
+                }
+                ScriptMyLocal wrlcl = gn.WritesLocal();
+                if((wrlcl != null) &&
+                    !currentBlock.localsWrittenBeforeRead.Contains(wrlcl) &&
+                    !currentBlock.localsReadBeforeWritten.Contains(wrlcl))
+                {
+                    currentBlock.localsWrittenBeforeRead.Add(wrlcl);
+                }
+            }
+
+            /*
+             * For every block we branch to, add that blocks readables to our list of readables,
+             * because we need to have those values valid on entry to our block.  But if we write the 
+             * variable before we can possibly branch to that block, then we don't need to have it valid 
+             * on entry to our block.  So basically it looks like the branch instruction is reading 
+             * everything required by any blocks it can branch to.
+             */
+            do
+            {
+                this.resolvedSomething = false;
+                this.resolveSequence++;
+                this.ResolveBlock((GraphNodeBlock)firstLin);
+            } while(this.resolvedSomething);
+
+            /*
+             * Repeat the cutting loops as long as we keep finding stuff.
+             */
+            bool didSomething;
+            do
+            {
+                didSomething = false;
+
+                /*
+                 * Strip out ldc.i4.1/xor/ldc.i4.1/xor
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if(!(gn is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit xor2 = (GraphNodeEmit)gn;
+                    if(xor2.opcode != OpCodes.Xor)
+                        continue;
+                    if(!(xor2.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit ld12 = (GraphNodeEmit)xor2.prevLin;
+                    if(ld12.opcode != OpCodes.Ldc_I4_1)
+                        continue;
+                    if(!(ld12.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit xor1 = (GraphNodeEmit)ld12.prevLin;
+                    if(xor1.opcode != OpCodes.Xor)
+                        continue;
+                    if(!(xor2.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit ld11 = (GraphNodeEmit)xor1.prevLin;
+                    if(ld11.opcode != OpCodes.Ldc_I4_1)
+                        continue;
+                    ld11.prevLin.nextLin = xor2.nextLin;
+                    xor2.nextLin.prevLin = ld11.prevLin;
+                    didSomething = true;
+                }
+
+                /*
+                 * Replace c{cond}/ldc.i4.1/xor/br{false,true} -> c{cond}/br{true,false}
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if(!(gn is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit brft = (GraphNodeEmit)gn;
+                    if((brft.opcode != OpCodes.Brfalse) && (brft.opcode != OpCodes.Brtrue))
+                        continue;
+                    if(!(brft.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit xor = (GraphNodeEmit)brft.prevLin;
+                    if(xor.opcode != OpCodes.Xor)
+                        continue;
+                    if(!(xor.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit ldc = (GraphNodeEmit)xor.prevLin;
+                    if(ldc.opcode != OpCodes.Ldc_I4_1)
+                        continue;
+                    if(!(ldc.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit cmp = (GraphNodeEmit)ldc.prevLin;
+                    if(cmp.opcode.StackBehaviourPop != StackBehaviour.Pop1_pop1)
+                        continue;
+                    if(cmp.opcode.StackBehaviourPush != StackBehaviour.Pushi)
+                        continue;
+                    cmp.nextLin = brft;
+                    brft.prevLin = cmp;
+                    brft.opcode = (brft.opcode == OpCodes.Brfalse) ? OpCodes.Brtrue : OpCodes.Brfalse;
+                    didSomething = true;
+                }
+
+                /*
+                 * Replace c{cond}/br{false,true} -> b{!,}{cond}
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if(!(gn is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit brft = (GraphNodeEmit)gn;
+                    if((brft.opcode != OpCodes.Brfalse) && (brft.opcode != OpCodes.Brtrue))
+                        continue;
+                    if(!(brft.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit cmp = (GraphNodeEmit)brft.prevLin;
+                    if(cmp.opcode.StackBehaviourPop != StackBehaviour.Pop1_pop1)
+                        continue;
+                    if(cmp.opcode.StackBehaviourPush != StackBehaviour.Pushi)
+                        continue;
+                    cmp.prevLin.nextLin = brft;
+                    brft.prevLin = cmp.prevLin;
+                    bool brtru = (brft.opcode == OpCodes.Brtrue);
+                    if(cmp.opcode == OpCodes.Ceq)
+                        brft.opcode = brtru ? OpCodes.Beq : OpCodes.Bne_Un;
+                    else if(cmp.opcode == OpCodes.Cgt)
+                        brft.opcode = brtru ? OpCodes.Bgt : OpCodes.Ble;
+                    else if(cmp.opcode == OpCodes.Cgt_Un)
+                        brft.opcode = brtru ? OpCodes.Bgt_Un : OpCodes.Ble_Un;
+                    else if(cmp.opcode == OpCodes.Clt)
+                        brft.opcode = brtru ? OpCodes.Blt : OpCodes.Bge;
+                    else if(cmp.opcode == OpCodes.Clt_Un)
+                        brft.opcode = brtru ? OpCodes.Blt_Un : OpCodes.Bge_Un;
+                    else
+                        throw new Exception();
+                    didSomething = true;
+                }
+
+                /*
+                 * Replace ld{c.i4.0,null}/br{ne.un,eq} -> br{true,false}
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if(!(gn is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit brcc = (GraphNodeEmit)gn;
+                    if((brcc.opcode != OpCodes.Bne_Un) && (brcc.opcode != OpCodes.Beq))
+                        continue;
+                    if(!(brcc.prevLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit ldc0 = (GraphNodeEmit)brcc.prevLin;
+                    if((ldc0.opcode != OpCodes.Ldc_I4_0) && (ldc0.opcode != OpCodes.Ldnull))
+                        continue;
+                    ldc0.prevLin.nextLin = brcc;
+                    brcc.prevLin = ldc0.prevLin;
+                    brcc.opcode = (brcc.opcode == OpCodes.Bne_Un) ? OpCodes.Brtrue : OpCodes.Brfalse;
+                    didSomething = true;
+                }
+
+                /*
+                 * Replace:
+                 *    ldloc v1
+                 *    stloc v2
+                 *    ld<anything> except ld<anything> v2
+                 *    ldloc v2
+                 *      ...v2 unreferenced hereafter
+                 * With:
+                 *    ld<anything> except ld<anything> v2
+                 *    ldloc v1
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+
+                    // check for 'ldloc v1' instruction
+                    if(!(gn is GraphNodeEmitLocal))
+                        continue;
+                    GraphNodeEmitLocal ldlv1 = (GraphNodeEmitLocal)gn;
+                    if(ldlv1.opcode != OpCodes.Ldloc)
+                        continue;
+
+                    // check for 'stloc v2' instruction
+                    if(!(ldlv1.nextLin is GraphNodeEmitLocal))
+                        continue;
+                    GraphNodeEmitLocal stlv2 = (GraphNodeEmitLocal)ldlv1.nextLin;
+                    if(stlv2.opcode != OpCodes.Stloc)
+                        continue;
+
+                    // check for 'ld<anything> except ld<anything> v2' instruction
+                    if(!(stlv2.nextLin is GraphNodeEmit))
+                        continue;
+                    GraphNodeEmit ldany = (GraphNodeEmit)stlv2.nextLin;
+                    if(!ldany.opcode.ToString().StartsWith("ld"))
+                        continue;
+                    if((ldany is GraphNodeEmitLocal) &&
+                        ((GraphNodeEmitLocal)ldany).myLocal == stlv2.myLocal)
+                        continue;
+
+                    // check for 'ldloc v2' instruction
+                    if(!(ldany.nextLin is GraphNodeEmitLocal))
+                        continue;
+                    GraphNodeEmitLocal ldlv2 = (GraphNodeEmitLocal)ldany.nextLin;
+                    if(ldlv2.opcode != OpCodes.Ldloc)
+                        continue;
+                    if(ldlv2.myLocal != stlv2.myLocal)
+                        continue;
+
+                    // check that v2 is not needed after this at all
+                    if(IsLocalNeededAfterThis(ldlv2, ldlv2.myLocal))
+                        continue;
+
+                    // make 'ld<anything>...' the first instruction
+                    ldany.prevLin = ldlv1.prevLin;
+                    ldany.prevLin.nextLin = ldany;
+
+                    // make 'ldloc v1' the second instruction
+                    ldany.nextLin = ldlv1;
+                    ldlv1.prevLin = ldany;
+
+                    // and make 'ldloc v1' the last instruction
+                    ldlv1.nextLin = ldlv2.nextLin;
+                    ldlv1.nextLin.prevLin = ldlv1;
+
+                    didSomething = true;
+                }
+
+                /*
+                 * Remove all the stloc/ldloc that are back-to-back without the local
+                 * being needed afterwards.  If it is needed afterwards, replace the 
+                 * stloc/ldloc with dup/stloc.
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if((gn is GraphNodeEmitLocal) &&
+                        (gn.prevLin is GraphNodeEmitLocal))
+                    {
+                        GraphNodeEmitLocal stloc = (GraphNodeEmitLocal)gn.prevLin;
+                        GraphNodeEmitLocal ldloc = (GraphNodeEmitLocal)gn;
+                        if((stloc.opcode == OpCodes.Stloc) &&
+                            (ldloc.opcode == OpCodes.Ldloc) &&
+                            (stloc.myLocal == ldloc.myLocal))
+                        {
+                            if(IsLocalNeededAfterThis(ldloc, ldloc.myLocal))
+                            {
+                                GraphNodeEmitNull dup = new GraphNodeEmitNull(this, stloc.errorAt, OpCodes.Dup);
+                                dup.nextLin = stloc;
+                                dup.prevLin = stloc.prevLin;
+                                stloc.nextLin = ldloc.nextLin;
+                                stloc.prevLin = dup;
+                                dup.prevLin.nextLin = dup;
+                                stloc.nextLin.prevLin = stloc;
+                                gn = stloc;
+                            }
+                            else
+                            {
+                                stloc.prevLin.nextLin = ldloc.nextLin;
+                                ldloc.nextLin.prevLin = stloc.prevLin;
+                                gn = stloc.prevLin;
+                            }
+                            didSomething = true;
+                        }
+                    }
+                }
+
+                /*
+                 * Remove all write-only local variables, ie, those with no ldloc[a] references.
+                 * Replace any stloc instructions with pops.
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    ScriptMyLocal rdlcl = gn.ReadsLocal();
+                    if(rdlcl != null)
+                        rdlcl.isReferenced = true;
+                }
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    ScriptMyLocal wrlcl = gn.WritesLocal();
+                    if((wrlcl != null) && !wrlcl.isReferenced)
+                    {
+                        if(!(gn is GraphNodeEmitLocal) || (((GraphNodeEmitLocal)gn).opcode != OpCodes.Stloc))
+                        {
+                            throw new Exception("expecting stloc");
+                        }
+                        GraphNodeEmitNull pop = new GraphNodeEmitNull(this, ((GraphNodeEmit)gn).errorAt, OpCodes.Pop);
+                        pop.nextLin = gn.nextLin;
+                        pop.prevLin = gn.prevLin;
+                        gn.nextLin.prevLin = pop;
+                        gn.prevLin.nextLin = pop;
+                        gn = pop;
+                        didSomething = true;
+                    }
+                }
+
+                /*
+                 * Remove any Ld<const>/Dup,Pop.
+                 */
+                for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+                {
+                    if((gn is GraphNodeEmit) &&
+                        (gn.nextLin is GraphNodeEmit))
+                    {
+                        GraphNodeEmit gne = (GraphNodeEmit)gn;
+                        GraphNodeEmit nne = (GraphNodeEmit)gn.nextLin;
+                        if(gne.isPoppable && (nne.opcode == OpCodes.Pop))
+                        {
+                            gne.prevLin.nextLin = nne.nextLin;
+                            nne.nextLin.prevLin = gne.prevLin;
+                            gn = gne.prevLin;
+                            didSomething = true;
+                        }
+                    }
+                }
+            } while(didSomething);
+
+            /*
+             * Dump out the results.
+             */
+            if(DEBUG)
+            {
+                Console.WriteLine("");
+                Console.WriteLine(methName);
+                Console.WriteLine("  resolveSequence=" + this.resolveSequence);
+
+                Console.WriteLine("  Locals:");
+                foreach(ScriptMyLocal loc in declaredLocals)
+                {
+                    Console.WriteLine("    " + loc.type.Name + "  " + loc.name);
+                }
+
+                Console.WriteLine("  Labels:");
+                foreach(ScriptMyLabel lbl in definedLabels)
+                {
+                    Console.WriteLine("    " + lbl.name);
+                }
+
+                Console.WriteLine("  Code:");
+                DumpCode();
+            }
+        }
+
+        private void DumpCode()
+        {
+            int linSeqNos = 0;
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                gn.linSeqNo = ++linSeqNos;
+            }
+            for(GraphNode gn = firstLin; gn != null; gn = gn.nextLin)
+            {
+                StringBuilder sb = new StringBuilder();
+                gn.DebStringExt(sb);
+                Console.WriteLine(sb.ToString());
+                if(gn is GraphNodeBlock)
+                {
+                    GraphNodeBlock gnb = (GraphNodeBlock)gn;
+                    foreach(ScriptMyLocal lcl in gnb.localsReadBeforeWritten)
+                    {
+                        Console.WriteLine("         reads " + lcl.name);
+                    }
+                }
+            }
+        }
+
+        /**
+         * @brief Scan the given block for branches to other blocks.
+         *        For any locals read by those blocks, mark them as being read by this block, 
+         *        provided this block has not written them by that point.  This makes it look 
+         *        as though the branch instruction is reading all the locals needed by any 
+         *        target blocks.
+         */
+        private void ResolveBlock(GraphNodeBlock currentBlock)
+        {
+            if(currentBlock.hasBeenResolved == this.resolveSequence)
+                return;
+
+            /*
+             * So we don't recurse forever on a backward branch.
+             */
+            currentBlock.hasBeenResolved = this.resolveSequence;
+
+            /*
+             * Assume we haven't written any locals yet.
+             */
+            List<ScriptMyLocal> localsWrittenSoFar = new List<ScriptMyLocal>();
+
+            /*
+             * Scan through the instructions in this block.
+             */
+            for(GraphNode gn = currentBlock; gn != null;)
+            {
+
+                /*
+                 * See if the instruction writes a local we don't know about yet.
+                 */
+                ScriptMyLocal wrlcl = gn.WritesLocal();
+                if((wrlcl != null) && !localsWrittenSoFar.Contains(wrlcl))
+                {
+                    localsWrittenSoFar.Add(wrlcl);
+                }
+
+                /*
+                 * Scan through all the possible next instructions after this.
+                 * Note that if we are in the first part of a try/catch/finally block, 
+                 * every instruction conditionally branches to the beginning of the 
+                 * second part (the catch/finally block).
+                 */
+                GraphNode nextFallthruNode = null;
+                foreach(GraphNode nn in gn.NextNodes)
+                {
+                    if(nn is GraphNodeBlock)
+                    {
+
+                        /*
+                         * Start of a block, go through all locals needed by that block on entry.
+                         */
+                        GraphNodeBlock nextBlock = (GraphNodeBlock)nn;
+                        ResolveBlock(nextBlock);
+                        foreach(ScriptMyLocal readByNextBlock in nextBlock.localsReadBeforeWritten)
+                        {
+
+                            /*
+                             * If this block hasn't written it by now and this block doesn't already
+                             * require it on entry, say this block requires it on entry.
+                             */
+                            if(!localsWrittenSoFar.Contains(readByNextBlock) &&
+                                !currentBlock.localsReadBeforeWritten.Contains(readByNextBlock))
+                            {
+                                currentBlock.localsReadBeforeWritten.Add(readByNextBlock);
+                                this.resolvedSomething = true;
+                            }
+                        }
+                    }
+                    else
+                    {
+
+                        /*
+                         * Not start of a block, should be normal fallthru instruction.
+                         */
+                        if(nextFallthruNode != null)
+                            throw new Exception("more than one fallthru from " + gn.ToString());
+                        nextFallthruNode = nn;
+                    }
+                }
+
+                /*
+                 * Process next instruction if it isn't the start of a block.
+                 */
+                if(nextFallthruNode == gn)
+                    throw new Exception("can't fallthru to self");
+                gn = nextFallthruNode;
+            }
+        }
+
+        /**
+         * @brief Figure out whether the value in a local var is needed after the given instruction.
+         *        True if we reach the end of the program on all branches before reading it
+         *        True if we write the local var on all branches before reading it
+         *        False otherwise
+         */
+        private bool IsLocalNeededAfterThis(GraphNode node, ScriptMyLocal local)
+        {
+            do
+            {
+                GraphNode nextFallthruNode = null;
+                foreach(GraphNode nn in node.NextNodes)
+                {
+                    if(nn is GraphNodeBlock)
+                    {
+                        if(((GraphNodeBlock)nn).localsReadBeforeWritten.Contains(local))
+                        {
+                            return true;
+                        }
+                    }
+                    else
+                    {
+                        nextFallthruNode = nn;
+                    }
+                }
+                node = nextFallthruNode;
+                if(node == null)
+                    return false;
+                if(node.ReadsLocal() == local)
+                    return true;
+            } while(node.WritesLocal() != local);
+            return false;
+        }
+
+        public static void PadToLength(StringBuilder sb, int len, string str)
+        {
+            int pad = len - sb.Length;
+            if(pad < 0)
+                pad = 0;
+            sb.Append(str.PadLeft(pad));
+        }
+    }
+}

+ 1882 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs

@@ -0,0 +1,1882 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using OpenSim.Region.ScriptEngine.Yengine;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * @brief Compute values used during code generation to keep track of where computed values are stored.
+ *
+ *        Conceptually holds the memory address and type of the value
+ *        such as that used for a local variable, global variable, temporary variable.
+ *        Also used for things like constants and function/method entrypoints,
+ *        they are basically treated as read-only variables.
+ *
+ *            cv.type - type of the value
+ *
+ *            cv.PushVal() - pushes the value on the CIL stack
+ *            cv.PushRef() - pushes address of the value on the CIL stack
+ *
+ *            cv.PopPre()  - gets ready to pop from the CIL stack
+ *                           ...by possibly pushing something
+ *                <push value to be popped>
+ *            cv.PushPre() - pops value from the CIL stack
+ *
+ *        If the type is a TokenTypeSDTypeDelegate, the location is callable, 
+ *        so you get these additional functions:
+ *
+ *            cv.GetRetType()  - gets function/method's return value type
+ *                               TokenTypeVoid if void
+ *                               null if not a delegate
+ *            cv.GetArgTypes() - gets array of argument types
+ *                               as seen by script level, ie, 
+ *                               does not include any hidden 'this' type
+ *            cv.GetArgSig()   - gets argument signature eg, "(integer,list)"
+ *                               null if not a delegate
+ *
+ *            cv.CallPre()     - gets ready to call the function/method
+ *                               ...by possibly pushing something
+ *                                  such as a 'this' pointer
+ *                <push call args left-to-right>
+ *            cv.CallPost()    - calls the function/method
+ */
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    /**
+     * @brief Location of a value
+     *        Includes constants, expressions and temp variables.
+     */
+    public abstract class CompValu
+    {
+        protected static readonly MethodInfo gsmdMethodInfo =
+                typeof(XMRInstAbstract).GetMethod("GetScriptMethodDelegate",
+                                                    new Type[] { typeof(string), typeof(string), typeof(object) });
+
+        private static readonly MethodInfo avpmListMethInfo = typeof(XMRInstArrays).GetMethod("PopList", new Type[] { typeof(int), typeof(LSL_List) });
+        private static readonly MethodInfo avpmObjectMethInfo = typeof(XMRInstArrays).GetMethod("PopObject", new Type[] { typeof(int), typeof(object) });
+        private static readonly MethodInfo avpmStringMethInfo = typeof(XMRInstArrays).GetMethod("PopString", new Type[] { typeof(int), typeof(string) });
+
+        public TokenType type;        // type of the value and where in the source it was used
+
+        public CompValu(TokenType type)
+        {
+            this.type = type;
+        }
+
+        public Type ToSysType()
+        {
+            return (type.ToLSLWrapType() != null) ? type.ToLSLWrapType() : type.ToSysType();
+        }
+
+        // if a field of an XMRInstArrays array cannot be directly written,
+        // get the method that can write it
+        private static MethodInfo ArrVarPopMeth(FieldInfo fi)
+        {
+            if(fi.Name == "iarLists")
+                return avpmListMethInfo;
+            if(fi.Name == "iarObjects")
+                return avpmObjectMethInfo;
+            if(fi.Name == "iarStrings")
+                return avpmStringMethInfo;
+            return null;
+        }
+
+        // emit code to push value onto stack
+        public void PushVal(ScriptCodeGen scg, Token errorAt, TokenType stackType)
+        {
+            this.PushVal(scg, errorAt, stackType, false);
+        }
+        public void PushVal(ScriptCodeGen scg, Token errorAt, TokenType stackType, bool explicitAllowed)
+        {
+            this.PushVal(scg, errorAt);
+            TypeCast.CastTopOfStack(scg, errorAt, this.type, stackType, explicitAllowed);
+        }
+        public abstract void PushVal(ScriptCodeGen scg, Token errorAt);
+        public abstract void PushRef(ScriptCodeGen scg, Token errorAt);
+
+        // emit code to pop value from stack
+        public void PopPost(ScriptCodeGen scg, Token errorAt, TokenType stackType)
+        {
+            TypeCast.CastTopOfStack(scg, errorAt, stackType, this.type, false);
+            this.PopPost(scg, errorAt);
+        }
+        public virtual void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+        }  // call this before pushing value to be popped
+        public abstract void PopPost(ScriptCodeGen scg, Token errorAt);   // call this after pushing value to be popped
+
+        // return true: doing a PushVal() does not involve CheckRun()
+        //       false: otherwise
+        public virtual bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return true;
+        }
+
+        /*
+         * These additional functions are available if the type is a delegate
+         */
+        public TokenType GetRetType()
+        {
+            if(!(type is TokenTypeSDTypeDelegate))
+                return null;
+            return ((TokenTypeSDTypeDelegate)type).decl.GetRetType();
+        }
+        public TokenType[] GetArgTypes()
+        {
+            if(!(type is TokenTypeSDTypeDelegate))
+                return null;
+            return ((TokenTypeSDTypeDelegate)type).decl.GetArgTypes();
+        }
+        public string GetArgSig()
+        {
+            if(!(type is TokenTypeSDTypeDelegate))
+                return null;
+            return ((TokenTypeSDTypeDelegate)type).decl.GetArgSig();
+        }
+
+        // These are used only if type is a delegate too
+        // - but it is a real delegate pointer in a global or local variable or a field, etc
+        //   ie, PushVal() pushes a delegate pointer
+        // - so we must have CallPre() push the delegate pointer as a 'this' for this.Invoke(...)
+        // - and CallPost() call the delegate's Invoke() method
+        // - we assume the target function is non-trivial so we always use a call label
+        public virtual void CallPre(ScriptCodeGen scg, Token errorAt)   // call this before pushing arguments
+        {
+            new ScriptCodeGen.CallLabel(scg, errorAt);
+            this.PushVal(scg, errorAt);
+        }
+        public virtual void CallPost(ScriptCodeGen scg, Token errorAt)  // call this after pushing arguments
+        {
+            TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
+            MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo();
+            scg.ilGen.Emit(errorAt, OpCodes.Callvirt, invokeMethodInfo);
+            scg.openCallLabel = null;
+        }
+
+        /*
+         * Utilities used by CompValuGlobalVar and CompValuInstField
+         * where the value is located in a type-dependent array.
+         */
+        protected void EmitFieldPushVal(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray);   // which array
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);  // which array element
+            if(type is TokenTypeFloat)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem_R8);
+            }
+            else if(type is TokenTypeInt)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem_I4);
+            }
+            else if(type is TokenTypeSDTypeDelegate)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(object));
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, ToSysType());
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, ToSysType());
+            }
+        }
+
+        protected void EmitFieldPushRef(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
+        {
+            if(ArrVarPopMeth(var.vTableArray) != null)
+            {
+                scg.ErrorMsg(errorAt, "can't take address of this variable");
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldelema, ToSysType());
+        }
+
+        protected void EmitFieldPopPre(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
+        {
+            if(ArrVarPopMeth(var.vTableArray) != null)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, var.vTableArray);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, var.vTableIndex);
+            }
+        }
+
+        protected void EmitFieldPopPost(ScriptCodeGen scg, Token errorAt, TokenDeclVar var)
+        {
+            if(ArrVarPopMeth(var.vTableArray) != null)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Call, ArrVarPopMeth(var.vTableArray));
+            }
+            else if(type is TokenTypeFloat)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Stelem_R8);
+            }
+            else if(type is TokenTypeInt)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Stelem_I4);
+            }
+            else if(type is TokenTypeSDTypeDelegate)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Stelem, typeof(object));
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Stelem, ToSysType());
+            }
+        }
+
+        /**
+         * @brief With value pushed on stack, emit code to set a property by calling its setter() method.
+         * @param scg = which script is being compiled
+         * @param errorAt = for error messages
+         * @param type = property type
+         * @param setProp = setter() method
+         */
+        protected void EmitPopPostProp(ScriptCodeGen scg, Token errorAt, TokenType type, CompValu setProp)
+        {
+            ScriptMyLocal temp = scg.ilGen.DeclareLocal(type.ToSysType(), "__spr_" + errorAt.Unique);
+            scg.ilGen.Emit(errorAt, OpCodes.Stloc, temp);
+            setProp.CallPre(scg, errorAt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldloc, temp);
+            setProp.CallPost(scg, errorAt);
+        }
+    }
+
+    // The value is kept in an (XMR_Array) array element
+    public class CompValuArEle: CompValu
+    {
+        public CompValu arr;
+        private CompValu idx;
+        private TokenTypeObject tto;
+
+        private static readonly MethodInfo getByKeyMethodInfo = typeof(XMR_Array).GetMethod("GetByKey",
+                                                                                              new Type[] { typeof(object) });
+        private static readonly MethodInfo setByKeyMethodInfo = typeof(XMR_Array).GetMethod("SetByKey",
+                                                                                              new Type[] { typeof (object),
+                                                                                                           typeof (object) });
+
+        // type = TokenTypeObject always, as our array elements are always of type 'object'
+        // arr  = where the array object itself is stored
+        // idx  = where the index value is stored
+        public CompValuArEle(TokenType type, CompValu arr, CompValu idx) : base(type)
+        {
+            this.arr = arr;
+            this.idx = idx;
+            this.tto = new TokenTypeObject(this.type);
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            arr.PushVal(scg, errorAt);   // array
+            idx.PushVal(scg, errorAt, this.tto);  // key
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getByKeyMethodInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "array element not allowed here");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            arr.PushVal(scg, errorAt);            // array
+            idx.PushVal(scg, errorAt, this.tto);  // key
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, setByKeyMethodInfo);
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading an
+        // XMR_Array element is trivial
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // The value is kept in the current function's argument list
+    public class CompValuArg: CompValu
+    {
+        public int index;
+        public bool readOnly;
+
+        private static OpCode[] ldargs = { OpCodes.Ldarg_0, OpCodes.Ldarg_1,
+                                           OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
+
+        public CompValuArg(TokenType type, int index) : base(type)
+        {
+            this.index = index;
+        }
+        public CompValuArg(TokenType type, int index, bool ro) : base(type)
+        {
+            this.index = index;
+            this.readOnly = ro;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if(index < ldargs.Length)
+                scg.ilGen.Emit(errorAt, ldargs[index]);
+            else if(index <= 255)
+                scg.ilGen.Emit(errorAt, OpCodes.Ldarg_S, index);
+            else
+                scg.ilGen.Emit(errorAt, OpCodes.Ldarg, index);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if(readOnly)
+            {
+                scg.ErrorMsg(errorAt, "location cannot be written to");
+            }
+            if(index <= 255)
+                scg.ilGen.Emit(errorAt, OpCodes.Ldarga_S, index);
+            else
+                scg.ilGen.Emit(errorAt, OpCodes.Ldarga, index);
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(readOnly)
+            {
+                scg.ErrorMsg(errorAt, "location cannot be written to");
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Starg, index);
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading an
+        // argument is trivial
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // The value is a character constant
+    public class CompValuChar: CompValu
+    {
+        public char x;
+
+        public CompValuChar(TokenType type, char x) : base(type)
+        {
+            if(!(this.type is TokenTypeChar))
+            {
+                this.type = new TokenTypeChar(this.type);
+            }
+            this.x = x;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, (int)x);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into contant");
+        }
+    }
+
+    // The value is kept in a struct/class field of an internal struct/class
+    public class CompValuField: CompValu
+    {
+        CompValu obj;
+        FieldInfo field;
+
+        public CompValuField(TokenType type, CompValu obj, FieldInfo field) : base(type)
+        {
+            this.obj = obj;
+            this.field = field;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if(field.ReflectedType.IsValueType)
+            {
+                obj.PushRef(scg, errorAt);
+            }
+            else
+            {
+                obj.PushVal(scg, errorAt);
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Ldfld, field);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if(field.ReflectedType.IsValueType)
+            {
+                obj.PushRef(scg, errorAt);
+            }
+            else
+            {
+                obj.PushVal(scg, errorAt);
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Ldflda, field);
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(field.ReflectedType.IsValueType)
+            {
+                obj.PushRef(scg, errorAt);
+            }
+            else
+            {
+                obj.PushVal(scg, errorAt);
+            }
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Stfld, field);
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading an
+        // field of a class/struct is trivial
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // Accessing an element of a fixed-dimension array
+    public class CompValuFixArEl: CompValu
+    {
+        private CompValu baseRVal;
+        private CompValu[] subRVals;
+
+        private int nSubs;
+        private TokenDeclVar getFunc;
+        private TokenDeclVar setFunc;
+        private TokenTypeInt tokenTypeInt;
+
+        /**
+         * @brief Set up to access an element of an array.
+         * @param scg = what script we are compiling
+         * @param baseRVal = what array we are accessing
+         * @param subRVals = the subscripts being applied
+         */
+        public CompValuFixArEl(ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals) : base(GetElementType(scg, baseRVal, subRVals))
+        {
+            this.baseRVal = baseRVal;  // location of the array itself
+            this.subRVals = subRVals;  // subscript values
+            this.nSubs = subRVals.Length;
+
+            TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
+            TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+            tokenTypeInt = new TokenTypeInt(sdtType);
+
+            TokenName name = new TokenName(sdtType, "Get");
+            TokenType[] argsig = new TokenType[nSubs];
+            for(int i = 0; i < nSubs; i++)
+            {
+                argsig[i] = tokenTypeInt;
+            }
+            getFunc = scg.FindThisMember(sdtDecl, name, argsig);
+
+            name = new TokenName(sdtType, "Set");
+            argsig = new TokenType[nSubs + 1];
+            for(int i = 0; i < nSubs; i++)
+            {
+                argsig[i] = tokenTypeInt;
+            }
+            argsig[nSubs] = getFunc.retType;
+            setFunc = scg.FindThisMember(sdtDecl, name, argsig);
+        }
+
+        /**
+         * @brief Read array element and push value on stack.
+         */
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            // call script-defined class' Get() method to fetch the value
+            baseRVal.PushVal(scg, errorAt);
+            for(int i = 0; i < nSubs; i++)
+            {
+                subRVals[i].PushVal(scg, errorAt, tokenTypeInt);
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getFunc.ilGen);
+        }
+
+        /**
+         * @brief Push address of array element on stack.
+         */
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("tu stOOpid to get array element address");
+        }
+
+        /**
+         * @brief Prepare to write array element.
+         */
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            // set up call to script-defined class' Set() method to write the value
+            baseRVal.PushVal(scg, errorAt);
+            for(int i = 0; i < nSubs; i++)
+            {
+                subRVals[i].PushVal(scg, errorAt, tokenTypeInt);
+            }
+        }
+
+        /**
+         * @brief Pop value from stack and write array element.
+         */
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            // call script-defined class' Set() method to write the value
+            scg.ilGen.Emit(errorAt, OpCodes.Call, setFunc.ilGen);
+        }
+
+        /**
+         * @brief Get the array element type by getting the Get() functions return type.
+         *        Crude but effective.
+         * @param scg = what script we are compiling
+         * @param baseRVal = what array we are accessing
+         * @param subRVals = the subscripts being applied
+         * @returns array element type
+         */
+        private static TokenType GetElementType(ScriptCodeGen scg, CompValu baseRVal, CompValu[] subRVals)
+        {
+            TokenTypeSDTypeClass sdtType = (TokenTypeSDTypeClass)baseRVal.type;
+            TokenDeclSDTypeClass sdtDecl = sdtType.decl;
+            TokenName name = new TokenName(sdtType, "Get");
+            int nSubs = subRVals.Length;
+            TokenType[] argsig = new TokenType[nSubs];
+            argsig[0] = new TokenTypeInt(sdtType);
+            for(int i = 0; ++i < nSubs;)
+            {
+                argsig[i] = argsig[0];
+            }
+            TokenDeclVar getFunc = scg.FindThisMember(sdtDecl, name, argsig);
+            return getFunc.retType;
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading an
+        // fixed-dimension array element is trivial
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // The value is a float constant
+    public class CompValuFloat: CompValu
+    {
+        public double x;
+
+        public CompValuFloat(TokenType type, double x) : base(type)
+        {
+            if(!(this.type is TokenTypeFloat))
+            {
+                this.type = new TokenTypeFloat(this.type);
+            }
+            this.x = x;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, x);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into constant");
+        }
+    }
+
+    // The value is the entrypoint of a script-defined global function.
+    // These are also used for script-defined type static methods as the calling convention is the same,
+    // ie, the XMRInstance pointer is a hidden first argument.
+    // There is just one of these created when the function is being compiled as there is only one value
+    // of the function.
+    public class CompValuGlobalMeth: CompValu
+    {
+        private TokenDeclVar func;
+
+        public CompValuGlobalMeth(TokenDeclVar declFunc) : base(declFunc.GetDelType())
+        {
+            this.func = declFunc;
+        }
+
+        /**
+         * @brief PushVal for a function/method means push a delegate on the stack.
+         *        We build a call to the DynamicMethod's CreateDelegate() function 
+         *        to create the delegate.  Slip the scriptinstance pointer as the 
+         *        function's arg 0 so it will get passed to the function when called.
+         */
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            string dtn = type.ToString();
+            if(dtn.StartsWith("delegate "))
+                dtn = dtn.Substring(9);
+
+            // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
+            //   where methName = [<sdtclass>.]<methname>(<argtypes>)
+            //        signature = <rettype>(<argtypes>)
+            //             arg0 = scriptinstance (XMRInstance)
+            scg.PushXMRInst();                                     // [0] scriptinstance
+            scg.ilGen.Emit(errorAt, OpCodes.Ldstr, func.ilGen.methName);    // [1] method name
+            scg.ilGen.Emit(errorAt, OpCodes.Ldstr, dtn);                    // [2] delegate type name
+            scg.PushXMRInst();                                     // [3] scriptinstance
+            scg.ilGen.Emit(errorAt, OpCodes.Callvirt, gsmdMethodInfo);      // [0] delegate instance
+            scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType());  // [0] cast to correct delegate class
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get ref to global method");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into global method");
+        }
+
+        /**
+         * @brief A direct call is much simpler than pushing a delegate.
+         *        Just push the XMRInstance pointer, push the args and finally call the function.
+         */
+        public override void CallPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(!this.func.IsFuncTrivial(scg))
+                new ScriptCodeGen.CallLabel(scg, errorAt);
+
+            // all script-defined global functions are static methods created by DynamicMethod()
+            // and the first argument is always the XMR_Instance pointer
+            scg.PushXMRInst();
+        }
+        public override void CallPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, func.ilGen);
+            if(!this.func.IsFuncTrivial(scg))
+                scg.openCallLabel = null;
+        }
+    }
+
+    // The value is in a script-global variable = ScriptModule instance variable
+    // It could also be a script-global property
+    public class CompValuGlobalVar: CompValu
+    {
+        private static readonly FieldInfo glblVarsFieldInfo = typeof(XMRInstAbstract).GetField("glblVars");
+
+        private TokenDeclVar declVar;
+
+        public CompValuGlobalVar(TokenDeclVar declVar, XMRInstArSizes glblSizes) : base(declVar.type)
+        {
+            this.declVar = declVar;
+            if((declVar.getProp == null) && (declVar.setProp == null))
+            {
+                declVar.type.AssignVarSlot(declVar, glblSizes);
+            }
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.getProp == null) && (declVar.setProp == null))
+            {
+                scg.PushXMRInst();
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
+                EmitFieldPushVal(scg, errorAt, declVar);
+            }
+            else if(declVar.getProp != null)
+            {
+                declVar.getProp.location.CallPre(scg, errorAt);
+                declVar.getProp.location.CallPost(scg, errorAt);
+            }
+            else
+            {
+                scg.ErrorMsg(errorAt, "property not readable");
+                scg.PushDefaultValue(declVar.type);
+            }
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.getProp == null) && (declVar.setProp == null))
+            {
+                scg.PushXMRInst();
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
+                EmitFieldPushRef(scg, errorAt, declVar);
+            }
+            else
+            {
+                scg.ErrorMsg(errorAt, "cannot get address of property");
+            }
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.getProp == null) && (declVar.setProp == null))
+            {
+                scg.PushXMRInst();
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, glblVarsFieldInfo);
+                EmitFieldPopPre(scg, errorAt, declVar);
+            }
+            else if(declVar.setProp == null)
+            {
+                scg.ErrorMsg(errorAt, "property not writable");
+            }
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.getProp == null) && (declVar.setProp == null))
+            {
+                EmitFieldPopPost(scg, errorAt, declVar);
+            }
+            else if(declVar.setProp != null)
+            {
+                EmitPopPostProp(scg, errorAt, declVar.type, declVar.setProp.location);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+            }
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading an
+        // global variable is trivial provided it is 
+        // not a property or the property function is
+        // trivial.
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l && ((declVar.getProp == null) || declVar.getProp.IsFuncTrivial(scg));
+        }
+    }
+
+    // The value is in an $idxprop property of a script-defined type class or interface instance.
+    // Reading and writing is via a method call.
+    public class CompValuIdxProp: CompValu
+    {
+        private TokenDeclVar idxProp;  // $idxprop property within baseRVal
+        private CompValu baseRVal;     // pointer to class or interface object containing property
+        private TokenType[] argTypes;  // argument types as required by $idxprop declaration
+        private CompValu[] indices;    // actual index values to pass to getter/setter method
+        private CompValu setProp;      // location of setter method
+
+        public CompValuIdxProp(TokenDeclVar idxProp, CompValu baseRVal, TokenType[] argTypes, CompValu[] indices) : base(idxProp.type)
+        {
+            this.idxProp = idxProp;
+            this.baseRVal = baseRVal;
+            this.argTypes = argTypes;
+            this.indices = indices;
+        }
+
+        /**
+         * @brief Pushing the property's value is a matter of calling the getter method
+         *        with the supplied argument list as is.
+         */
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if(idxProp.getProp != null)
+            {
+                if(!idxProp.getProp.IsFuncTrivial(scg))
+                {
+                    for(int i = indices.Length; --i >= 0;)
+                    {
+                        indices[i] = scg.Trivialize(indices[i], errorAt);
+                    }
+                }
+                CompValu getProp = GetIdxPropMeth(idxProp.getProp);
+                getProp.CallPre(scg, errorAt);
+                for(int i = 0; i < indices.Length; i++)
+                {
+                    indices[i].PushVal(scg, errorAt, argTypes[i]);
+                }
+                getProp.CallPost(scg, errorAt);
+            }
+            else
+            {
+                // write-only property
+                scg.ErrorMsg(errorAt, "member not readable");
+                scg.PushDefaultValue(idxProp.type);
+            }
+        }
+
+        /**
+         * @brief A property does not have a memory address.
+         */
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "member has no address");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+
+        /**
+         * @brief Preparing to write a property consists of preparing to call the setter method
+         *        then pushing the index arguments.
+         */
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(idxProp.setProp != null)
+            {
+                if(!idxProp.setProp.IsFuncTrivial(scg))
+                {
+                    for(int i = indices.Length; --i >= 0;)
+                    {
+                        indices[i] = scg.Trivialize(indices[i], errorAt);
+                    }
+                }
+                this.setProp = GetIdxPropMeth(idxProp.setProp);
+                this.setProp.CallPre(scg, errorAt);
+                for(int i = 0; i < indices.Length; i++)
+                {
+                    indices[i].PushVal(scg, errorAt, argTypes[i]);
+                }
+            }
+            else
+            {
+                // read-only property
+                scg.ErrorMsg(errorAt, "member not writable");
+            }
+        }
+
+        /**
+         * @brief Finishing writing a property consists of finishing the call to the setter method
+         *        now that the value to be written has been pushed by our caller.
+         */
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(idxProp.setProp != null)
+            {
+                this.setProp.CallPost(scg, errorAt);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+            }
+        }
+
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            // if no getter, reading would throw an error, so doesn't really matter what we say
+            if(idxProp.getProp == null)
+                return true;
+
+            // assume interface methods are always non-trivial because we don't know anything about the actual implementation
+            if(baseRVal.type is TokenTypeSDTypeInterface)
+                return false;
+
+            // accessing it in any way can't be trivial if reading the pointer isn't trivial
+            if(!baseRVal.IsReadTrivial(scg, readAt))
+                return false;
+
+            // likewise with the indices
+            foreach(CompValu idx in indices)
+            {
+                if(!idx.IsReadTrivial(scg, readAt))
+                    return false;
+            }
+
+            // now the only way it can be non-trivial to read is if the getter() method itself is non-trivial.
+            return idxProp.getProp.IsFuncTrivial(scg);
+        }
+
+        /**
+         * @brief Get how to call the getter or setter method.
+         */
+        private CompValu GetIdxPropMeth(TokenDeclVar meth)
+        {
+            if(baseRVal.type is TokenTypeSDTypeClass)
+            {
+                return new CompValuInstMember(meth, baseRVal, false);
+            }
+            return new CompValuIntfMember(meth, baseRVal);
+        }
+    }
+
+    // This represents the type and location of an internally-defined function
+    // that a script can call
+    public class CompValuInline: CompValu
+    {
+        public TokenDeclInline declInline;
+
+        public CompValuInline(TokenDeclInline declInline) : base(declInline.GetDelType())
+        {
+            this.declInline = declInline;
+        }
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot use built-in for delegate, wrap it");
+            scg.ilGen.Emit(errorAt, OpCodes.Pop);
+        }
+    }
+
+    // The value is the entrypoint of a script-defined type's interface method combined with
+    // the pointer used to access the method.  Thus there is one of these per call site.
+    // They also handle accessing interface properties.
+    public class CompValuIntfMember: CompValu
+    {
+        private TokenDeclVar declVar;
+        private CompValu baseRVal;
+
+        public CompValuIntfMember(TokenDeclVar declVar, CompValu baseRVal) : base(declVar.type)
+        {
+            if(this.type == null)
+                throw new Exception("interface member type is null");
+            this.declVar = declVar;   // which element of the baseRVal vector to be accessed
+            this.baseRVal = baseRVal;  // the vector of delegates implementing the interface
+        }
+
+        /**
+         * @brief Reading a method's value means getting a delegate to that method.
+         *        Reading a property's value means calling the getter method for that property.
+         */
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.retType != null)
+            {
+                baseRVal.PushVal(scg, errorAt);                        // push pointer to delegate array on stack
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select which delegate to access
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate));     // push delegate on stack
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType());  // cast to correct delegate class
+            }
+            else if(declVar.getProp != null)
+            {
+                CompValu getProp = new CompValuIntfMember(declVar.getProp, baseRVal);
+                getProp.CallPre(scg, errorAt);                        // reading property, call its getter
+                getProp.CallPost(scg, errorAt);                        // ... with no arguments
+            }
+            else
+            {
+                scg.ErrorMsg(errorAt, "member not readable");
+                scg.PushDefaultValue(declVar.type);
+            }
+        }
+
+        /**
+         * @brief Can't get the address of either a method or a property.
+         */
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "member has no address");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+
+        /**
+         * @brief Can't write a method.
+         *        For property, it means calling the setter method for that property.
+         */
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.setProp == null)
+            {
+                // read-only property
+                scg.ErrorMsg(errorAt, "member not writable");
+            }
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.setProp != null)
+            {
+                CompValu setProp = new CompValuIntfMember(declVar.setProp, baseRVal);
+                EmitPopPostProp(scg, errorAt, declVar.type, setProp);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+            }
+        }
+
+        /**
+         * @brief Reading a method (ie, it's delegate) is always trivial, it's just retrieving
+         *        an element from the delegate array that make up the interface object.
+         *
+         *        Reading a property is always non-trivial because we don't know which implementation 
+         *        the interface is pointing to, so we don't know if it's trivial or not, so assume 
+         *        the worst, ie, that it is non-trivial and might call CheckRun().
+         *
+         *        But all that assumes that locating the interface object in the first place is 
+         *        trivial, ie, baseRVal.PushVal() must not call CheckRun() either.
+         */
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return baseRVal.IsReadTrivial(scg, readAt) && (declVar.getProp == null);
+        }
+
+        /**
+         * @brief We just defer to the default CallPre() and CallPost() methods.
+         *        They expect this.PushVal() to push a delegate to the method to be called.
+         *        If this member is a method, our PushVal() will read the correct element 
+         *        of the iTable array and push it on the stack, ready for Invoke() to be
+         *        called.  If this member is a property, the only way it can be called is 
+         *        if the property is a delegate, in which case PushVal() will retrieve the 
+         *        delegate by calling the property's getter method.
+         */
+    }
+
+    // The value is the entrypoint of an internal instance method
+    // such as XMR_Array.index()
+    public class CompValuIntInstMeth: CompValu
+    {
+        private TokenTypeSDTypeDelegate delType;
+        private CompValu baseRVal;
+        private MethodInfo methInfo;
+
+        public CompValuIntInstMeth(TokenTypeSDTypeDelegate delType, CompValu baseRVal, MethodInfo methInfo) : base(delType)
+        {
+            this.delType = delType;
+            this.baseRVal = baseRVal;
+            this.methInfo = methInfo;
+        }
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            // its value, ie, without applying the (arglist), is a delegate...
+            baseRVal.PushVal(scg, errorAt);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldftn, methInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, delType.decl.GetConstructorInfo());
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get ref to instance method");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into instance method");
+        }
+
+        public override void CallPre(ScriptCodeGen scg, Token errorAt)
+        {
+            // internal instance methods are always trivial so never need a CallLabel.
+            baseRVal.PushVal(scg, errorAt);
+        }
+        public override void CallPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
+        }
+    }
+
+    // The value is fetched by calling an internal instance method
+    // such as XMR_Array.count
+    public class CompValuIntInstROProp: CompValu
+    {
+        private CompValu baseRVal;
+        private MethodInfo methInfo;
+
+        public CompValuIntInstROProp(TokenType valType, CompValu baseRVal, MethodInfo methInfo) : base(valType)
+        {
+            this.baseRVal = baseRVal;
+            this.methInfo = methInfo;
+        }
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            baseRVal.PushVal(scg, errorAt);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot get ref to read-only property");
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot store into read-only property");
+            scg.ilGen.Emit(errorAt, OpCodes.Pop);
+        }
+    }
+
+    // The value is in a member of a script-defined type class instance.
+    //       field: value is in one of the arrays contained within XMRSDTypeClObj.instVars
+    //      method: value is a delegate; can be called
+    //    property: reading and writing is via a method call
+    public class CompValuInstMember: CompValu
+    {
+        private static readonly FieldInfo instVarsFieldInfo = typeof(XMRSDTypeClObj).GetField("instVars");
+        private static readonly FieldInfo vTableFieldInfo = typeof(XMRSDTypeClObj).GetField("sdtcVTable");
+
+        private TokenDeclVar declVar;  // member being accessed
+        private CompValu baseRVal;     // pointer to particular object instance
+        private bool ignoreVirt;       // ignore virtual attribute; use declVar's non-virtual method/property
+
+        public CompValuInstMember(TokenDeclVar declVar, CompValu baseRVal, bool ignoreVirt) : base(declVar.type)
+        {
+            this.declVar = declVar;
+            this.baseRVal = baseRVal;
+            this.ignoreVirt = ignoreVirt;
+        }
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.retType != null)
+            {
+                // a method's value, ie, without applying the (arglist), is a delegate...
+                PushValMethod(scg, errorAt);
+            }
+            else if(declVar.vTableArray != null)
+            {
+                // a field's value is its XMRSDTypeClObj.instVars array element
+                baseRVal.PushVal(scg, errorAt);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
+                EmitFieldPushVal(scg, errorAt, declVar);
+            }
+            else if(declVar.getProp != null)
+            {
+                // a property's value is calling its get method with no arguments
+                CompValu getProp = new CompValuInstMember(declVar.getProp, baseRVal, ignoreVirt);
+                getProp.CallPre(scg, errorAt);
+                getProp.CallPost(scg, errorAt);
+            }
+            else
+            {
+                // write-only property
+                scg.ErrorMsg(errorAt, "member not readable");
+                scg.PushDefaultValue(declVar.type);
+            }
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.vTableArray != null)
+            {
+                // a field's value is its XMRSDTypeClObj.instVars array element
+                baseRVal.PushVal(scg, errorAt);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
+                EmitFieldPushRef(scg, errorAt, declVar);
+            }
+            else
+            {
+                scg.ErrorMsg(errorAt, "member has no address");
+                scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+            }
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.vTableArray != null)
+            {
+                // a field's value is its XMRSDTypeClObj.instVars array element
+                baseRVal.PushVal(scg, errorAt);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, instVarsFieldInfo);
+                EmitFieldPopPre(scg, errorAt, declVar);
+            }
+            else if(declVar.setProp == null)
+            {
+                // read-only property
+                scg.ErrorMsg(errorAt, "member not writable");
+            }
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.vTableArray != null)
+            {
+                EmitFieldPopPost(scg, errorAt, declVar);
+            }
+            else if(declVar.setProp != null)
+            {
+                CompValu setProp = new CompValuInstMember(declVar.setProp, baseRVal, ignoreVirt);
+                EmitPopPostProp(scg, errorAt, declVar.type, setProp);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+            }
+        }
+
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            // accessing it in any way can't be trivial if reading the pointer isn't trivial.
+            // this also handles strict right-to-left mode detection as the side-effect can
+            // only apply to the pointer (it can't change which field or method we access).
+            if(!baseRVal.IsReadTrivial(scg, readAt))
+                return false;
+
+            // now the only way it can be non-trivial to read is if it is a property and the 
+            // getter() method is non-trivial.  reading a method means getting a delegate 
+            // which is always trivial, and reading a simple field is always trivial, ie, no 
+            // CheckRun() call can possibly be involved.
+            if(declVar.retType != null)
+            {
+                // a method's value, ie, without applying the (arglist), is a delegate...
+                return true;
+            }
+            if(declVar.vTableArray != null)
+            {
+                // a field's value is its XMRSDTypeClObj.instVars array element
+                return true;
+            }
+            if(declVar.getProp != null)
+            {
+                // a property's value is calling its get method with no arguments
+                return declVar.getProp.IsFuncTrivial(scg);
+            }
+
+            // write-only property
+            return true;
+        }
+
+        public override void CallPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.retType != null)
+            {
+                CallPreMethod(scg, errorAt);
+            }
+            else
+            {
+                base.CallPre(scg, errorAt);
+            }
+        }
+        public override void CallPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(declVar.retType != null)
+            {
+                CallPostMethod(scg, errorAt);
+            }
+            else
+            {
+                base.CallPost(scg, errorAt);
+            }
+        }
+
+        /**
+         * @brief A PushVal() for a method means to push a delegate for the method on the stack.
+         */
+        private void PushValMethod(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+                throw new Exception("dont use for statics");
+
+            if(ignoreVirt || (declVar.vTableIndex < 0))
+            {
+
+                /*
+                 * Non-virtual instance method, create a delegate that references the method.
+                 */
+                string dtn = type.ToString();
+
+                // delegateinstance = (signature)scriptinstance.GetScriptMethodDelegate (methName, signature, arg0);
+                //   where methName = <sdtclass>.<methname>(<argtypes>)
+                //        signature = <rettype>(<argtypes>)
+                //             arg0 = sdt istance (XMRSDTypeClObj) 'this' value
+                scg.PushXMRInst();                                     // [0] scriptinstance
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, declVar.ilGen.methName); // [1] method name
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, dtn);                    // [2] delegate type name
+                baseRVal.PushVal(scg, errorAt);                        // [3] sdtinstance
+                scg.ilGen.Emit(errorAt, OpCodes.Callvirt, gsmdMethodInfo);      // [0] delegate instance
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType());  // [0] cast to correct delegate class
+            }
+            else
+            {
+
+                /*
+                 * Virtual instance method, get the delegate from the vtable.
+                 */
+                baseRVal.PushVal(scg, errorAt);                                 // 'this' selecting the instance
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, vTableFieldInfo);        // get pointer to instance's vtable array
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select vtable element
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate));     // get delegate pointer = 'this' for 'Invoke()'
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType());  // cast to correct delegate class
+            }
+        }
+
+        private void CallPreMethod(ScriptCodeGen scg, Token errorAt)
+        {
+            if((declVar.sdtFlags & ScriptReduce.SDT_STATIC) != 0)
+                throw new Exception("dont use for statics");
+
+            if(!this.declVar.IsFuncTrivial(scg))
+                new ScriptCodeGen.CallLabel(scg, errorAt);
+
+            if(ignoreVirt || (declVar.vTableIndex < 0))
+            {
+                baseRVal.PushVal(scg, errorAt);                                 // 'this' being passed directly to method
+            }
+            else
+            {
+                baseRVal.PushVal(scg, errorAt);                                 // 'this' selecting the instance
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, vTableFieldInfo);        // get pointer to instance's vtable array
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, declVar.vTableIndex);   // select vtable element
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate));     // get delegate pointer = 'this' for 'Invoke()'
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, type.ToSysType());  // cast to correct delegate class
+            }
+        }
+        private void CallPostMethod(ScriptCodeGen scg, Token errorAt)
+        {
+            if(ignoreVirt || (declVar.vTableIndex < 0))
+            {
+                // non-virt instance, just call function directly
+                scg.ilGen.Emit(errorAt, OpCodes.Call, declVar.ilGen);
+            }
+            else
+            {
+                // virtual, call via delegate Invoke(...) method
+                TokenTypeSDTypeDelegate ttd = (TokenTypeSDTypeDelegate)type;
+                MethodInfo invokeMethodInfo = ttd.decl.GetInvokerInfo();
+                scg.ilGen.Emit(errorAt, OpCodes.Callvirt, invokeMethodInfo);
+            }
+
+            if(!this.declVar.IsFuncTrivial(scg))
+                scg.openCallLabel = null;
+        }
+    }
+
+    // The value is an integer constant
+    public class CompValuInteger: CompValu
+    {
+        public int x;
+
+        public CompValuInteger(TokenType type, int x) : base(type)
+        {
+            if(!(this.type is TokenTypeInt))
+            {
+                this.type = new TokenTypeInt(this.type);
+            }
+            this.x = x;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, x);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into constant");
+        }
+    }
+
+    // The value is an element of a list
+    public class CompValuListEl: CompValu
+    {
+        private static readonly MethodInfo getElementFromListMethodInfo =
+                 typeof(CompValuListEl).GetMethod("GetElementFromList", new Type[] { typeof(LSL_List), typeof(int) });
+
+        private CompValu theList;
+        private CompValu subscript;
+
+        public CompValuListEl(TokenType type, CompValu theList, CompValu subscript) : base(type)
+        {
+            this.theList = theList;
+            this.subscript = subscript;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            theList.PushVal(scg, errorAt, new TokenTypeList(type));
+            subscript.PushVal(scg, errorAt, new TokenTypeInt(type));
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getElementFromListMethodInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get list element's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot store into list element");
+            scg.ilGen.Emit(errorAt, OpCodes.Pop);
+        }
+
+        public static object GetElementFromList(LSL_List lis, int idx)
+        {
+            object element = lis.Data[idx];
+            if(element is LSL_Float)
+                return TypeCast.EHArgUnwrapFloat(element);
+            if(element is LSL_Integer)
+                return TypeCast.EHArgUnwrapInteger(element);
+            if(element is LSL_String)
+                return TypeCast.EHArgUnwrapString(element);
+            if(element is OpenMetaverse.Quaternion)
+                return TypeCast.EHArgUnwrapRotation(element);
+            if(element is OpenMetaverse.Vector3)
+                return TypeCast.EHArgUnwrapVector(element);
+            return element;
+        }
+    }
+
+    // The value is kept in a script-addressable local variable
+    public class CompValuLocalVar: CompValu
+    {
+        private static int htpopseq = 0;
+
+        private ScriptMyLocal localBuilder;
+
+        public CompValuLocalVar(TokenType type, string name, ScriptCodeGen scg) : base(type)
+        {
+            if(type.ToHeapTrackerType() != null)
+            {
+                this.localBuilder = scg.ilGen.DeclareLocal(type.ToHeapTrackerType(), name);
+                scg.PushXMRInst();
+                scg.ilGen.Emit(type, OpCodes.Newobj, type.GetHeapTrackerCtor());
+                scg.ilGen.Emit(type, OpCodes.Stloc, localBuilder);
+            }
+            else
+            {
+                this.localBuilder = scg.ilGen.DeclareLocal(ToSysType(), name);
+            }
+        }
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
+            if(type.ToHeapTrackerType() != null)
+            {
+                type.CallHeapTrackerPushMeth(errorAt, scg.ilGen);
+            }
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if(type.ToHeapTrackerType() != null)
+            {
+                scg.ErrorMsg(errorAt, "can't take ref of heap-tracked type " + type.ToString());
+                scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldloca, localBuilder);
+            }
+        }
+
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+            if(type.ToHeapTrackerType() != null)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
+            }
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if(type.ToHeapTrackerType() != null)
+            {
+                type.CallHeapTrackerPopMeth(errorAt, scg.ilGen);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
+            }
+        }
+
+        public void Pop(ScriptCodeGen scg, Token errorAt)
+        {
+            if(type.ToHeapTrackerType() != null)
+            {
+                /*
+                 * Popping into a heap tracker wrapped local variable.
+                 * First pop value into a temp var, then call the heap tracker's pop method.
+                 */
+                ScriptMyLocal htpop = scg.ilGen.DeclareLocal(type.ToSysType(), "htpop$" + (++htpopseq).ToString());
+                scg.ilGen.Emit(errorAt, OpCodes.Stloc, htpop);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldloc, htpop);
+                type.CallHeapTrackerPopMeth(errorAt, scg.ilGen);
+            }
+            else
+            {
+
+                /*
+                 * Not a heap-tracked local var, just pop directly into it.
+                 */
+                scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
+            }
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading a
+        // local variable is trivial.
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // The value is a null
+    public class CompValuNull: CompValu
+    {
+        public CompValuNull(TokenType type) : base(type) { }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldnull);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get null's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into null");
+        }
+    }
+
+    // The value is a rotation
+    public class CompValuRot: CompValu
+    {
+        public CompValu x;
+        public CompValu y;
+        public CompValu z;
+        public CompValu w;
+
+        private static readonly ConstructorInfo lslRotConstructorInfo =
+                typeof(LSL_Rotation).GetConstructor(new Type[] { typeof (double),
+                                                                   typeof (double),
+                                                                   typeof (double),
+                                                                   typeof (double) });
+
+        public CompValuRot(TokenType type, CompValu x, CompValu y, CompValu z, CompValu w) :
+                base(type)
+        {
+            if(!(type is TokenTypeRot))
+            {
+                this.type = new TokenTypeRot(type);
+            }
+            this.x = x;
+            this.y = y;
+            this.z = z;
+            this.w = w;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            this.x.PushVal(scg, errorAt, new TokenTypeFloat(this.x.type));
+            this.y.PushVal(scg, errorAt, new TokenTypeFloat(this.y.type));
+            this.z.PushVal(scg, errorAt, new TokenTypeFloat(this.z.type));
+            this.w.PushVal(scg, errorAt, new TokenTypeFloat(this.w.type));
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslRotConstructorInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into constant");
+        }
+
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            // the supplied values must be trivial because when we call their PushVal()s
+            // there will be stuff on the stack for all but the first PushVal() and so
+            // they would have a non-empty stack at their call label.
+            if(!this.w.IsReadTrivial(scg, readAt) ||
+                !this.x.IsReadTrivial(scg, readAt) ||
+                !this.y.IsReadTrivial(scg, readAt) ||
+                !this.z.IsReadTrivial(scg, readAt))
+            {
+                throw new Exception("rotation values must be trivial");
+            }
+
+            return true;
+        }
+    }
+
+    // The value is in a static field of an internally defined struct/class
+    public class CompValuSField: CompValu
+    {
+        public FieldInfo field;
+
+        public CompValuSField(TokenType type, FieldInfo field) : base(type)
+        {
+            this.field = field;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            if((field.Attributes & FieldAttributes.Literal) == 0)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldsfld, field);
+                return;
+            }
+            if(field.FieldType == typeof(LSL_Rotation))
+            {
+                LSL_Rotation rot = (LSL_Rotation)field.GetValue(null);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.x);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.y);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.z);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, rot.s);
+                scg.ilGen.Emit(errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
+                return;
+            }
+            if(field.FieldType == typeof(LSL_Vector))
+            {
+                LSL_Vector vec = (LSL_Vector)field.GetValue(null);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.x);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.y);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_R8, vec.z);
+                scg.ilGen.Emit(errorAt, OpCodes.Newobj, ScriptCodeGen.lslRotationConstructorInfo);
+                return;
+            }
+            if(field.FieldType == typeof(string))
+            {
+                string str = (string)field.GetValue(null);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, str);
+                return;
+            }
+            throw new Exception("unsupported literal type " + field.FieldType.Name);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            if((field.Attributes & FieldAttributes.Literal) != 0)
+            {
+                throw new Exception("can't write a constant");
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Ldflda, field);
+        }
+        public override void PopPre(ScriptCodeGen scg, Token errorAt)
+        {
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            if((field.Attributes & FieldAttributes.Literal) != 0)
+            {
+                throw new Exception("can't write a constant");
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Stsfld, field);
+        }
+
+        // non-trivial because it needs to be copied into a temp
+        // in case the idiot does dumb-ass side effects tricks
+        //   eg,  (x = 0) + x + 2
+        //   should read old value of x not 0
+        // but if 'xmroption norighttoleft;' in effect,
+        // we can read it in any order so reading a
+        // local variable is trivial.
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            return readAt.nr2l;
+        }
+    }
+
+    // The value is a character within a string
+    public class CompValuStrChr: CompValu
+    {
+        private static readonly MethodInfo getCharFromStringMethodInfo =
+                 typeof(CompValuStrChr).GetMethod("GetCharFromString", new Type[] { typeof(string), typeof(int) });
+
+        private CompValu theString;
+        private CompValu subscript;
+
+        public CompValuStrChr(TokenType type, CompValu theString, CompValu subscript) : base(type)
+        {
+            this.theString = theString;
+            this.subscript = subscript;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            theString.PushVal(scg, errorAt, new TokenTypeStr(type));
+            subscript.PushVal(scg, errorAt, new TokenTypeInt(type));
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getCharFromStringMethodInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get string character's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ErrorMsg(errorAt, "cannot store into string character");
+            scg.ilGen.Emit(errorAt, OpCodes.Pop);
+        }
+
+        public static char GetCharFromString(string s, int i)
+        {
+            return s[i];
+        }
+    }
+
+    // The value is a key or string constant
+    public class CompValuString: CompValu
+    {
+        public string x;
+
+        public CompValuString(TokenType type, string x) : base(type)
+        {
+            if(!(type is TokenTypeKey) && !(this.type is TokenTypeStr))
+            {
+                throw new Exception("bad type " + type.ToString());
+            }
+            this.x = x;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldstr, x);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into constant");
+        }
+    }
+
+    // The value is kept in a temp local variable
+    public class CompValuTemp: CompValu
+    {
+        public ScriptMyLocal localBuilder;
+
+        public CompValuTemp(TokenType type, ScriptCodeGen scg) : base(type)
+        {
+            string name = "tmp$" + (++scg.tempCompValuNum);
+            this.localBuilder = scg.ilGen.DeclareLocal(ToSysType(), name);
+        }
+        protected CompValuTemp(TokenType type) : base(type) { }  // CompValuVoid uses this
+
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldloca, localBuilder);
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Stloc, localBuilder);
+        }
+        public void Pop(ScriptCodeGen scg, Token errorAt, TokenType stackType)
+        {
+            TypeCast.CastTopOfStack(scg, errorAt, stackType, this.type, false);
+            this.PopPost(scg, errorAt);  // in case PopPost() overridden eg by CompValuVoid
+        }
+        public void Pop(ScriptCodeGen scg, Token errorAt)
+        {
+            this.PopPost(scg, errorAt);  // in case PopPost() overridden eg by CompValuVoid
+        }
+    }
+
+    // The value is a vector
+    public class CompValuVec: CompValu
+    {
+        public CompValu x;
+        public CompValu y;
+        public CompValu z;
+
+        private static readonly ConstructorInfo lslVecConstructorInfo =
+                typeof(LSL_Vector).GetConstructor(new Type[] { typeof (double),
+                                                                 typeof (double),
+                                                                 typeof (double) });
+
+        public CompValuVec(TokenType type, CompValu x, CompValu y, CompValu z) : base(type)
+        {
+            if(!(type is TokenTypeVec))
+            {
+                this.type = new TokenTypeVec(type);
+            }
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+            this.x.PushVal(scg, errorAt, new TokenTypeFloat(this.x.type));
+            this.y.PushVal(scg, errorAt, new TokenTypeFloat(this.y.type));
+            this.z.PushVal(scg, errorAt, new TokenTypeFloat(this.z.type));
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslVecConstructorInfo);
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get constant's address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot store into constant");
+        }
+
+        public override bool IsReadTrivial(ScriptCodeGen scg, Token readAt)
+        {
+            // the supplied values must be trivial because when we call their PushVal()s
+            // there will be stuff on the stack for all but the first PushVal() and so
+            // they would have a non-empty stack at their call label.
+            if(!this.x.IsReadTrivial(scg, readAt) ||
+                !this.y.IsReadTrivial(scg, readAt) ||
+                !this.z.IsReadTrivial(scg, readAt))
+            {
+                throw new Exception("vector values must be trivial");
+            }
+
+            return true;
+        }
+    }
+
+    // Used to indicate value will be discarded (eg, where to put return value from a call)
+    public class CompValuVoid: CompValuTemp
+    {
+        public CompValuVoid(Token token) : base((token is TokenTypeVoid) ? (TokenTypeVoid)token : new TokenTypeVoid(token))
+        {
+        }
+        public override void PushVal(ScriptCodeGen scg, Token errorAt)
+        {
+        }
+        public override void PushRef(ScriptCodeGen scg, Token errorAt)
+        {
+            throw new Exception("cannot get void address");
+        }
+        public override void PopPost(ScriptCodeGen scg, Token errorAt)
+        {
+        }
+    }
+}

+ 77 - 98
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompile.cs → OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs

@@ -31,12 +31,8 @@
 
 using System;
 using System.IO;
-using System.IO.Compression;
-using System.Reflection;
-using System.Security.Cryptography;
-using System.Text;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public partial class XMRInstance
     {
@@ -45,155 +41,136 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @returns object code pointer or null if compile error
          *          also can throw compile error exception
          */
-        public ScriptObjCode Compile ()
+        public ScriptObjCode Compile()
         {
-            bool oldObjFile = false;
             Stream objFileStream = null;
             StreamWriter asmFileWriter = null;
-            string envar = null;
             string sourceHash = null;
             TextWriter saveSource = null;
 
-            string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
-            string lslFileName = GetScriptFileName (m_ScriptObjCodeKey + ".lsl");
             string objFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrobj");
             string tmpFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrtmp");
 
-            /*
-             * If we already have an object file, don't bother compiling.
-             */
-            if (!m_ForceRecomp && File.Exists (objFileName)) {
+             // If we already have an object file, don't bother compiling.
+            if (!m_ForceRecomp && File.Exists(objFileName))
+            {
                 objFileStream = File.OpenRead (objFileName);
-                oldObjFile = true;
-            } else {
-
-                /*
-                 * If source file empty, try to read from asset server.
-                 */
-                if (EmptySource (m_SourceCode)) {
+            }
+            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.
-                 */
-                envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveSource");
-                if ((envar != null) && ((envar[0] & 1) != 0)) {
-                    m_log.Debug ("[XMREngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
+                 // 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.
-                 */
+                 // Parse source string into tokens.
                 TokenBegin tokenBegin;
-                try {
+                try
+                {
                     tokenBegin = TokenBegin.Construct(m_CameFrom, saveSource, ErrorHandler, m_SourceCode, out sourceHash);
-                } finally {
-                    if (saveSource != null) saveSource.Close ();
                 }
-                if (tokenBegin == null) {
-                    m_log.Debug ("[XMREngine]: parsing errors on " + m_ScriptObjCodeKey);
+                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 object file one way or another.
+                try
+                {
                     objFileStream = File.Create (tmpFileName);
 
-                    /*
-                     * Create abstract syntax tree from raw tokens.
-                     */
+                     // Create abstract syntax tree from raw tokens.
                     TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin);
-                    if (tokenScript == null) {
-                        m_log.Warn ("[XMREngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
-                        PrintCompilerErrors ();
+                    if (tokenScript == null)
+                    {
+                        m_log.Warn ("[YEngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
+                        PrintCompilerErrors();
+                        objFileStream.Close();
                         return null;
                     }
 
-                    /*
-                     * Compile abstract syntax tree to write object file.
-                     */
+                     // Compile abstract syntax tree to write object file.
                     BinaryWriter objFileWriter = new BinaryWriter (objFileStream);
                     bool ok = ScriptCodeGen.CodeGen(tokenScript, objFileWriter, sourceHash);
-                    if (!ok) {
-                        m_log.Warn ("[XMREngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
+                    if (!ok)
+                    {
+                        m_log.Warn ("[YEngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
                         PrintCompilerErrors ();
-                        objFileStream.Close ();
+                        objFileWriter.Close ();
                         return null;
                     }
-                    objFileStream.Close ();
-
-                    /*
-                     * 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)) {
+                    objFileWriter.Close ();
+
+                     // 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 {
+                    else
                         File.Move (tmpFileName, objFileName);
-                    }
-                    objFileStream = File.OpenRead (objFileName);
-                } finally {
 
-                    /*
-                     * In case something went wrong writing temp file, delete it.
-                     */
-                    try {
+                    objFileStream = File.OpenRead (objFileName);
+                }
+                finally
+                {
+                     // In case something went wrong writing temp file, delete it.
+                    try
+                    {
                         File.Delete (tmpFileName);
-                    } catch {
+                    }
+                    catch
+                    {
                     }
                 }
 
-                /*
-                 * Since we just wrote the .xmrobj file, maybe save disassembly.
-                 */
-                envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveILGen");
-                if ((envar != null) && ((envar[0] & 1) != 0)) {
-                    m_log.Debug ("[XMREngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
+                 // Since we just wrote the .xmrobj file, maybe save disassembly.
+                if (m_Engine.m_ScriptDebugSaveIL)
+                {
+                    string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
+//                    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.
-             */
+             // 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 {
+            try
+            {
                 scriptObjCode = new ScriptObjCode (objFileReader, asmFileWriter, null);
-                if (scriptObjCode != null) {
-                    scriptObjCode.fileDateUtc = File.GetLastWriteTimeUtc (objFileName);
-                }
-            } finally {
+            }
+            finally
+            {
                 objFileReader.Close ();
-                if (asmFileWriter != null) {
+                if (asmFileWriter != null)
+                 {
                     asmFileWriter.Flush ();
                     asmFileWriter.Close ();
                 }
             }
 
-            /*
-             * Maybe an old object file has reached its expiration date.
-             */
-            if (oldObjFile && (scriptObjCode != null) && scriptObjCode.IsExpired ()) {
-                m_log.Debug ("[XMREngine]: expiration reached on " + m_ScriptObjCodeKey + ", reloading");
-                m_ForceRecomp = true;
-                scriptObjCode = Compile ();
-            }
-
             return scriptObjCode;
         }
 
         private void PrintCompilerErrors ()
         {
-            m_log.Info ("[XMREngine]: - " + m_Part.GetWorldPosition () + " " + m_DescName);
+            m_log.Info ("[YEngine]: - " + m_Part.GetWorldPosition () + " " + m_DescName);
             foreach (string error in m_CompilerErrors) {
-                m_log.Info ("[XMREngine]: - " + error);
+                m_log.Info ("[YEngine]: - " + error);
             }
         }
 
@@ -204,11 +181,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         {
             int len = source.Length;
             bool skipeol = false;
-            for (int i = 0; i < len; i ++) {
+            for (int i = 0; i < len; i ++)
+            {
                 char c = source[i];
                 skipeol &= c != '\n';
                 skipeol |= (c == '/') && (i + 1 < len) && (source[i+1] == '/');
-                if ((c > ' ') && !skipeol) return false;
+                if ((c > ' ') && !skipeol)
+                    return false;
             }
             return true;
         }

+ 287 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptConsts.cs

@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    public class ScriptConst
+    {
+
+        public static Dictionary<string, ScriptConst> scriptConstants = Init();
+
+        /**
+         * @brief look up the value of a given built-in constant.
+         * @param name = name of constant
+         * @returns null: no constant by that name defined
+         *          else: pointer to ScriptConst struct
+         */
+        public static ScriptConst Lookup(string name)
+        {
+            ScriptConst sc;
+            if(!scriptConstants.TryGetValue(name, out sc))
+                sc = null;
+            return sc;
+        }
+
+        private static Dictionary<string, ScriptConst> Init()
+        {
+            Dictionary<string, ScriptConst> sc = new Dictionary<string, ScriptConst>();
+
+            /*
+             * For every event code, define XMREVENTCODE_<eventname> and XMREVENTMASKn_<eventname> symbols.
+             */
+            for(int i = 0; i < 64; i++)
+            {
+                try
+                {
+                    string s = ((ScriptEventCode)i).ToString();
+                    if((s.Length > 0) && (s[0] >= 'a') && (s[0] <= 'z'))
+                    {
+                        new ScriptConst(sc,
+                                         "XMREVENTCODE_" + s,
+                                         new CompValuInteger(new TokenTypeInt(null), i));
+                        int n = i / 32 + 1;
+                        int m = 1 << (i % 32);
+                        new ScriptConst(sc,
+                                         "XMREVENTMASK" + n + "_" + s,
+                                         new CompValuInteger(new TokenTypeInt(null), m));
+                    }
+                }
+                catch { }
+            }
+
+            /*
+             * Also get all the constants from XMRInstAbstract and ScriptBaseClass etc as well.
+             */
+            for(Type t = typeof(XMRInstAbstract); t != typeof(object); t = t.BaseType)
+            {
+                AddInterfaceConstants(sc, t.GetFields());
+            }
+
+            return sc;
+        }
+
+        /**
+         * @brief Add all constants defined by the given interface.
+         */
+        // this one accepts only upper-case named fields
+        public static void AddInterfaceConstants(Dictionary<string, ScriptConst> sc, FieldInfo[] allFields)
+        {
+            List<FieldInfo> ucfs = new List<FieldInfo>(allFields.Length);
+            foreach(FieldInfo f in allFields)
+            {
+                string fieldName = f.Name;
+                int i;
+                for(i = fieldName.Length; --i >= 0;)
+                {
+                    if("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".IndexOf(fieldName[i]) < 0)
+                        break;
+                }
+                if(i < 0)
+                    ucfs.Add(f);
+            }
+            AddInterfaceConstants(sc, ucfs.GetEnumerator());
+        }
+
+        // this one accepts all fields given to it
+        public static void AddInterfaceConstants(Dictionary<string, ScriptConst> sc, IEnumerator<FieldInfo> fields)
+        {
+            if(sc == null)
+                sc = scriptConstants;
+
+            for(fields.Reset(); fields.MoveNext();)
+            {
+                FieldInfo constField = fields.Current;
+                Type fieldType = constField.FieldType;
+                CompValu cv;
+
+                /*
+                 * The location of a simple number is the number itself.
+                 * Access to the value gets compiled as an ldc instruction.
+                 */
+                if(fieldType == typeof(double))
+                {
+                    cv = new CompValuFloat(new TokenTypeFloat(null),
+                                            (double)(double)constField.GetValue(null));
+                }
+                else if(fieldType == typeof(int))
+                {
+                    cv = new CompValuInteger(new TokenTypeInt(null),
+                                              (int)constField.GetValue(null));
+                }
+                else if(fieldType == typeof(LSL_Integer))
+                {
+                    cv = new CompValuInteger(new TokenTypeInt(null),
+                                              ((LSL_Integer)constField.GetValue(null)).value);
+                }
+
+                /*
+                 * The location of a string is the string itself.
+                 * Access to the value gets compiled as an ldstr instruction.
+                 */
+                else if(fieldType == typeof(string))
+                {
+                    cv = new CompValuString(new TokenTypeStr(null),
+                                             (string)constField.GetValue(null));
+                }
+                else if(fieldType == typeof(LSL_String))
+                {
+                    cv = new CompValuString(new TokenTypeStr(null),
+                                             (string)(LSL_String)constField.GetValue(null));
+                }
+
+                /*
+                 * The location of everything else (objects) is the static field in the interface definition.
+                 * Access to the value gets compiled as an ldsfld instruction.
+                 */
+                else
+                {
+                    cv = new CompValuSField(TokenType.FromSysType(null, fieldType), constField);
+                }
+
+                /*
+                 * Add to dictionary.
+                 */
+                new ScriptConst(sc, constField.Name, cv);
+            }
+        }
+
+        /**
+         * @brief Add arbitrary constant available to script compilation.
+         * CAUTION: These values get compiled-in to a script and must not
+         *          change over time as previously compiled scripts will
+         *          still have the old values.
+         */
+        public static ScriptConst AddConstant(string name, object value)
+        {
+            CompValu cv = null;
+
+            if(value is char)
+            {
+                cv = new CompValuChar(new TokenTypeChar(null), (char)value);
+            }
+            if(value is double)
+            {
+                cv = new CompValuFloat(new TokenTypeFloat(null), (double)(double)value);
+            }
+            if(value is float)
+            {
+                cv = new CompValuFloat(new TokenTypeFloat(null), (double)(float)value);
+            }
+            if(value is int)
+            {
+                cv = new CompValuInteger(new TokenTypeInt(null), (int)value);
+            }
+            if(value is string)
+            {
+                cv = new CompValuString(new TokenTypeStr(null), (string)value);
+            }
+
+            if(value is LSL_Float)
+            {
+                cv = new CompValuFloat(new TokenTypeFloat(null), (double)((LSL_Float)value).value);
+            }
+            if(value is LSL_Integer)
+            {
+                cv = new CompValuInteger(new TokenTypeInt(null), ((LSL_Integer)value).value);
+            }
+            if(value is LSL_Rotation)
+            {
+                LSL_Rotation r = (LSL_Rotation)value;
+                CompValu x = new CompValuFloat(new TokenTypeFloat(null), r.x);
+                CompValu y = new CompValuFloat(new TokenTypeFloat(null), r.y);
+                CompValu z = new CompValuFloat(new TokenTypeFloat(null), r.z);
+                CompValu s = new CompValuFloat(new TokenTypeFloat(null), r.s);
+                cv = new CompValuRot(new TokenTypeRot(null), x, y, z, s);
+            }
+            if(value is LSL_String)
+            {
+                cv = new CompValuString(new TokenTypeStr(null), (string)(LSL_String)value);
+            }
+            if(value is LSL_Vector)
+            {
+                LSL_Vector v = (LSL_Vector)value;
+                CompValu x = new CompValuFloat(new TokenTypeFloat(null), v.x);
+                CompValu y = new CompValuFloat(new TokenTypeFloat(null), v.y);
+                CompValu z = new CompValuFloat(new TokenTypeFloat(null), v.z);
+                cv = new CompValuVec(new TokenTypeVec(null), x, y, z);
+            }
+
+            if(value is OpenMetaverse.Quaternion)
+            {
+                OpenMetaverse.Quaternion r = (OpenMetaverse.Quaternion)value;
+                CompValu x = new CompValuFloat(new TokenTypeFloat(null), r.X);
+                CompValu y = new CompValuFloat(new TokenTypeFloat(null), r.Y);
+                CompValu z = new CompValuFloat(new TokenTypeFloat(null), r.Z);
+                CompValu s = new CompValuFloat(new TokenTypeFloat(null), r.W);
+                cv = new CompValuRot(new TokenTypeRot(null), x, y, z, s);
+            }
+            if(value is OpenMetaverse.UUID)
+            {
+                cv = new CompValuString(new TokenTypeKey(null), value.ToString());
+            }
+            if(value is OpenMetaverse.Vector3)
+            {
+                OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)value;
+                CompValu x = new CompValuFloat(new TokenTypeFloat(null), v.X);
+                CompValu y = new CompValuFloat(new TokenTypeFloat(null), v.Y);
+                CompValu z = new CompValuFloat(new TokenTypeFloat(null), v.Z);
+                cv = new CompValuVec(new TokenTypeVec(null), x, y, z);
+            }
+
+            if(cv == null)
+                throw new Exception("bad type " + value.GetType().Name);
+            return new ScriptConst(scriptConstants, name, cv);
+        }
+
+        /*
+         * Instance variables
+         */
+        public string name;
+        public CompValu rVal;
+
+        private ScriptConst(Dictionary<string, ScriptConst> lc, string name, CompValu rVal)
+        {
+            lc.Add(name, this);
+            this.name = name;
+            this.rVal = rVal;
+        }
+    }
+}

+ 41 - 39
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptEventCode.cs → OpenSim/Region/ScriptEngine/YEngine/MMRScriptEventCode.cs

@@ -25,7 +25,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-namespace OpenSim.Region.ScriptEngine.XMREngine {
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
 
     /**
      * @brief List of event codes that can be passed to StartEventHandler().
@@ -38,58 +39,59 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
      *        in range 0..63 that begin with a lower-case letter for scripts to
      *        reference.
      */
-    public enum ScriptEventCode : int {
+    public enum ScriptEventCode: int
+    {
 
         // used by XMRInstance to indicate no event being processed
-        None                 = -1,
+        None = -1,
 
         // must be bit numbers of equivalent values in ...
         // OpenSim.Region.ScriptEngine.Shared.ScriptBase.scriptEvents
         // ... so they can be passed to m_Part.SetScriptEvents().
-        attach               =  0,
-        state_exit           =  1,
-        timer                =  2,
-        touch                =  3,
-        collision            =  4,
-        collision_end        =  5,
-        collision_start      =  6,
-        control              =  7,
-        dataserver           =  8,
-        email                =  9,
-        http_response        = 10,
-        land_collision       = 11,
-        land_collision_end   = 12,
+        attach = 0,
+        state_exit = 1,
+        timer = 2,
+        touch = 3,
+        collision = 4,
+        collision_end = 5,
+        collision_start = 6,
+        control = 7,
+        dataserver = 8,
+        email = 9,
+        http_response = 10,
+        land_collision = 11,
+        land_collision_end = 12,
         land_collision_start = 13,
-        at_target            = 14,
-        listen               = 15,
-        money                = 16,
-        moving_end           = 17,
-        moving_start         = 18,
-        not_at_rot_target    = 19,
-        not_at_target        = 20,
-        touch_start          = 21,
-        object_rez           = 22,
-        remote_data          = 23,
-        at_rot_target        = 24,
-        transaction_result   = 25,
+        at_target = 14,
+        listen = 15,
+        money = 16,
+        moving_end = 17,
+        moving_start = 18,
+        not_at_rot_target = 19,
+        not_at_target = 20,
+        touch_start = 21,
+        object_rez = 22,
+        remote_data = 23,
+        at_rot_target = 24,
+        transaction_result = 25,
         run_time_permissions = 28,
-        touch_end            = 29,
-        state_entry          = 30,
+        touch_end = 29,
+        state_entry = 30,
 
         // events not passed to m_Part.SetScriptEvents().
-        changed              = 33,
-        link_message         = 34,
-        no_sensor            = 35,
-        on_rez               = 36,
-        sensor               = 37,
-        http_request         = 38,
+        changed = 33,
+        link_message = 34,
+        no_sensor = 35,
+        on_rez = 36,
+        sensor = 37,
+        http_request = 38,
 
-        path_update          = 40,
+        path_update = 40,
 
         // XMRE specific
-        region_cross         = 63,
+        region_cross = 63,
 
         // marks highest numbered event, ie, number of columns in seht.
-        Size                 = 64
+        Size = 64
     }
 }

+ 727 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptInlines.cs

@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * @brief Generate code for the backend API calls.
+ */
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public abstract class TokenDeclInline: TokenDeclVar
+    {
+        public static VarDict inlineFunctions = CreateDictionary();
+
+        public abstract void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args);
+
+        private static string[] noCheckRuns;
+        private static string[] keyReturns;
+
+        protected bool isTaggedCallsCheckRun;
+
+        /**
+         * @brief Create a dictionary of inline backend API functions.
+         */
+        private static VarDict CreateDictionary()
+        {
+            /*
+             * For those listed in noCheckRun, we just generate the call (simple computations).
+             * For all others, we generate the call then a call to CheckRun().
+             */
+            noCheckRuns = new string[] {
+                "llBase64ToString",
+                "llCSV2List",
+                "llDeleteSubList",
+                "llDeleteSubString",
+                "llDumpList2String",
+                "llEscapeURL",
+                "llEuler2Rot",
+                "llGetListEntryType",
+                "llGetListLength",
+                "llGetSubString",
+                "llGetUnixTime",
+                "llInsertString",
+                "llList2CSV",
+                "llList2Float",
+                "llList2Integer",
+                "llList2Key",
+                "llList2List",
+                "llList2ListStrided",
+                "llList2Rot",
+                "llList2String",
+                "llList2Vector",
+                "llListFindList",
+                "llListInsertList",
+                "llListRandomize",
+                "llListReplaceList",
+                "llListSort",
+                "llListStatistics",
+                "llMD5String",
+                "llParseString2List",
+                "llParseStringKeepNulls",
+                "llRot2Euler",
+                "llStringLength",
+                "llStringToBase64",
+                "llStringTrim",
+                "llSubStringIndex",
+                "llUnescapeURL"
+            };
+
+            /*
+             * These functions really return a 'key' even though we see them as
+             * returning 'string' because OpenSim has key and string as same type.
+             */
+            keyReturns = new string[] {
+                "llAvatarOnLinkSitTarget",
+                "llAvatarOnSitTarget",
+                "llDetectedKey",
+                "llDetectedOwner",
+                "llGenerateKey",
+                "llGetCreator",
+                "llGetInventoryCreator",
+                "llGetInventoryKey",
+                "llGetKey",
+                "llGetLandOwnerAt",
+                "llGetLinkKey",
+                "llGetNotecardLine",
+                "llGetNumberOfNotecardLines",
+                "llGetOwner",
+                "llGetOwnerKey",
+                "llGetPermissionsKey",
+                "llHTTPRequest",
+                "llList2Key",
+                "llRequestAgentData",
+                "llRequestDisplayName",
+                "llRequestInventoryData",
+                "llRequestSecureURL",
+                "llRequestSimulatorData",
+                "llRequestURL",
+                "llRequestUsername",
+                "llSendRemoteData",
+                "llTransferLindenDollars"
+            };
+
+            VarDict ifd = new VarDict(false);
+
+            Type[] oneDoub = new Type[] { typeof(double) };
+            Type[] twoDoubs = new Type[] { typeof(double), typeof(double) };
+
+            /*
+             * Mono generates an FPU instruction for many math calls.
+             */
+            new TokenDeclInline_LLAbs(ifd);
+            new TokenDeclInline_Math(ifd, "llAcos(float)", "Acos", oneDoub);
+            new TokenDeclInline_Math(ifd, "llAsin(float)", "Asin", oneDoub);
+            new TokenDeclInline_Math(ifd, "llAtan2(float,float)", "Atan2", twoDoubs);
+            new TokenDeclInline_Math(ifd, "llCos(float)", "Cos", oneDoub);
+            new TokenDeclInline_Math(ifd, "llFabs(float)", "Abs", oneDoub);
+            new TokenDeclInline_Math(ifd, "llLog(float)", "Log", oneDoub);
+            new TokenDeclInline_Math(ifd, "llLog10(float)", "Log10", oneDoub);
+            new TokenDeclInline_Math(ifd, "llPow(float,float)", "Pow", twoDoubs);
+            new TokenDeclInline_LLRound(ifd);
+            new TokenDeclInline_Math(ifd, "llSin(float)", "Sin", oneDoub);
+            new TokenDeclInline_Math(ifd, "llSqrt(float)", "Sqrt", oneDoub);
+            new TokenDeclInline_Math(ifd, "llTan(float)", "Tan", oneDoub);
+
+            /*
+             * Something weird about the code generation for these calls, so they all have their own handwritten code generators.
+             */
+            new TokenDeclInline_GetFreeMemory(ifd);
+            new TokenDeclInline_GetUsedMemory(ifd);
+
+            /*
+             * These are all the xmr...() calls directly in XMRInstAbstract.
+             * Includes the calls from ScriptBaseClass that has all the stubs
+             * which convert XMRInstAbstract to the various <NAME>_Api contexts.
+             */
+            MethodInfo[] absmeths = typeof(XMRInstAbstract).GetMethods();
+            AddInterfaceMethods(ifd, absmeths, null);
+
+            return ifd;
+        }
+
+        /**
+         * @brief Add API functions from the given interface to list of built-in functions.
+         *        Only functions beginning with a lower-case letter are entered, all others ignored.
+         * @param ifd = internal function dictionary to add them to
+         * @param ifaceMethods = list of API functions
+         * @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer
+         */
+        // this one accepts only names beginning with a lower-case letter
+        public static void AddInterfaceMethods(VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf)
+        {
+            List<MethodInfo> lcms = new List<MethodInfo>(ifaceMethods.Length);
+            foreach(MethodInfo meth in ifaceMethods)
+            {
+                string name = meth.Name;
+                if((name[0] >= 'a') && (name[0] <= 'z'))
+                {
+                    lcms.Add(meth);
+                }
+            }
+            AddInterfaceMethods(ifd, lcms.GetEnumerator(), acf);
+        }
+
+        // this one accepts all methods given to it
+        public static void AddInterfaceMethods(VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf)
+        {
+            if(ifd == null)
+                ifd = inlineFunctions;
+
+            for(ifaceMethods.Reset(); ifaceMethods.MoveNext();)
+            {
+                MethodInfo ifaceMethod = ifaceMethods.Current;
+                string key = ifaceMethod.Name;
+
+                try
+                {
+                    /*
+                     * See if we will generate a call to CheckRun() right 
+                     * after we generate a call to the function.
+                     * If function begins with xmr, assume we will not call CheckRun()
+                     * Otherwise, assume we will call CheckRun()
+                     */
+                    bool dcr = !key.StartsWith("xmr");
+                    foreach(string ncr in noCheckRuns)
+                    {
+                        if(ncr == key)
+                        {
+                            dcr = false;
+                            break;
+                        }
+                    }
+
+                    /*
+                     * Add function to dictionary.
+                     */
+                    new TokenDeclInline_BEApi(ifd, dcr, ifaceMethod, acf);
+                }
+                catch
+                {
+                    ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
+                    ///???                          and OVERLOADED NAMES ???///
+                }
+            }
+        }
+
+        /**
+         * @brief Add an inline function definition to the dictionary.
+         * @param ifd        = dictionary to add inline definition to
+         * @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun()
+         * @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...)
+         * @param retType    = return type, use TokenTypeVoid if no return value
+         */
+        protected TokenDeclInline(VarDict ifd,
+                                   bool doCheckRun,
+                                   string nameArgSig,
+                                   TokenType retType)
+                : base(null, null, null)
+        {
+            this.retType = retType;
+            this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial;
+
+            int j = nameArgSig.IndexOf('(');
+            this.name = new TokenName(null, nameArgSig.Substring(0, j++));
+
+            this.argDecl = new TokenArgDecl(null);
+            if(nameArgSig[j] != ')')
+            {
+                int i;
+                TokenName name;
+                TokenType type;
+
+                for(i = j; nameArgSig[i] != ')'; i++)
+                {
+                    if(nameArgSig[i] == ',')
+                    {
+                        type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
+                        name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
+                        this.argDecl.AddArg(type, name);
+                        j = i + 1;
+                    }
+                }
+
+                type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
+                name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
+                this.argDecl.AddArg(type, name);
+            }
+
+            this.location = new CompValuInline(this);
+            if(ifd == null)
+                ifd = inlineFunctions;
+            ifd.AddEntry(this);
+        }
+
+        protected TokenDeclInline(VarDict ifd,
+                                   bool doCheckRun,
+                                   MethodInfo methInfo)
+                : base(null, null, null)
+        {
+            TokenType retType = TokenType.FromSysType(null, methInfo.ReturnType);
+
+            this.isTaggedCallsCheckRun = IsTaggedCallsCheckRun(methInfo);
+            this.name = new TokenName(null, methInfo.Name);
+            this.retType = GetRetType(methInfo, retType);
+            this.argDecl = GetArgDecl(methInfo.GetParameters());
+            this.triviality = (doCheckRun || this.isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial;
+            this.location = new CompValuInline(this);
+
+            if(ifd == null)
+                ifd = inlineFunctions;
+            ifd.AddEntry(this);
+        }
+
+        private static TokenArgDecl GetArgDecl(ParameterInfo[] parameters)
+        {
+            TokenArgDecl argDecl = new TokenArgDecl(null);
+            foreach(ParameterInfo pi in parameters)
+            {
+                TokenType type = TokenType.FromSysType(null, pi.ParameterType);
+                TokenName name = new TokenName(null, pi.Name);
+                argDecl.AddArg(type, name);
+            }
+            return argDecl;
+        }
+
+        /**
+         * @brief The above code assumes all methods beginning with 'xmr' are trivial, ie, 
+         *        they do not call CheckRun() and also we do not generate a CheckRun() 
+         *        call after they return.  So if an 'xmr' method does call CheckRun(), it 
+         *        must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know 
+         *        the method is not trivial.  But in neither case do we emit our own call 
+         *        to CheckRun(), the 'xmr' method must do its own.  We do however set up a
+         *        call label before the call to the non-trivial 'xmr' method so when we are
+         *        restoring the call stack, the restore will call directly in to the 'xmr'
+         *        method without re-executing any code before the call to the 'xmr' method.
+         */
+        private static bool IsTaggedCallsCheckRun(MethodInfo methInfo)
+        {
+            return (methInfo != null) &&
+                Attribute.IsDefined(methInfo, typeof(xmrMethodCallsCheckRunAttribute));
+        }
+
+        /**
+         * @brief The dumbass OpenSim has key and string as the same type so non-ll
+         *        methods must be tagged with xmrMethodReturnsKeyAttribute if we
+         *        are to think they return a key type, otherwise we will think they
+         *        return string.
+         */
+        private static TokenType GetRetType(MethodInfo methInfo, TokenType retType)
+        {
+            if((methInfo != null) && (retType != null) && (retType is TokenTypeStr))
+            {
+                if(Attribute.IsDefined(methInfo, typeof(xmrMethodReturnsKeyAttribute)))
+                {
+                    return ChangeToKeyType(retType);
+                }
+
+                string mn = methInfo.Name;
+                foreach(string kr in keyReturns)
+                {
+                    if(kr == mn)
+                        return ChangeToKeyType(retType);
+                }
+
+            }
+            return retType;
+        }
+        private static TokenType ChangeToKeyType(TokenType retType)
+        {
+            if(retType is TokenTypeLSLString)
+            {
+                retType = new TokenTypeLSLKey(null);
+            }
+            else
+            {
+                retType = new TokenTypeKey(null);
+            }
+            return retType;
+        }
+
+        public virtual MethodInfo GetMethodInfo()
+        {
+            return null;
+        }
+
+        /**
+         * @brief Print out a list of all the built-in functions and constants.
+         */
+        public delegate void WriteLine(string str);
+        public static void PrintBuiltins(bool inclNoisyTag, WriteLine writeLine)
+        {
+            writeLine("\nBuilt-in functions:\n");
+            SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline>();
+            foreach(TokenDeclVar bif in TokenDeclInline.inlineFunctions)
+            {
+                bifs.Add(bif.fullName, (TokenDeclInline)bif);
+            }
+            foreach(TokenDeclInline bif in bifs.Values)
+            {
+                char noisy = (!inclNoisyTag || !IsTaggedNoisy(bif.GetMethodInfo())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R';
+                writeLine(noisy + "   " + bif.retType.ToString().PadLeft(8) + " " + bif.fullName);
+            }
+            if(inclNoisyTag)
+            {
+                writeLine("\nN - stub that writes name and arguments to stdout");
+                writeLine("R - stub that writes name and arguments to stdout then reads return value from stdin");
+                writeLine("    format is:  function_name : return_value");
+                writeLine("      example:  llKey2Name:\"Kunta Kinte\"");
+            }
+
+            writeLine("\nBuilt-in constants:\n");
+            SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst>();
+            int widest = 0;
+            foreach(ScriptConst sc in ScriptConst.scriptConstants.Values)
+            {
+                if(widest < sc.name.Length)
+                    widest = sc.name.Length;
+                scs.Add(sc.name, sc);
+            }
+            foreach(ScriptConst sc in scs.Values)
+            {
+                writeLine("    " + sc.rVal.type.ToString().PadLeft(8) + " " + sc.name.PadRight(widest) + " = " + BuiltInConstVal(sc.rVal));
+            }
+        }
+
+        public static bool IsTaggedNoisy(MethodInfo methInfo)
+        {
+            return (methInfo != null) && Attribute.IsDefined(methInfo, typeof(xmrMethodIsNoisyAttribute));
+        }
+
+        public static string BuiltInConstVal(CompValu rVal)
+        {
+            if(rVal is CompValuInteger)
+            {
+                int x = ((CompValuInteger)rVal).x;
+                return "0x" + x.ToString("X8") + " = " + x.ToString().PadLeft(11);
+            }
+            if(rVal is CompValuFloat)
+                return ((CompValuFloat)rVal).x.ToString();
+            if(rVal is CompValuString)
+            {
+                StringBuilder sb = new StringBuilder();
+                PrintParam(sb, ((CompValuString)rVal).x);
+                return sb.ToString();
+            }
+            if(rVal is CompValuSField)
+            {
+                FieldInfo fi = ((CompValuSField)rVal).field;
+                StringBuilder sb = new StringBuilder();
+                PrintParam(sb, fi.GetValue(null));
+                return sb.ToString();
+            }
+            return rVal.ToString();  // just prints the type
+        }
+
+        public static void PrintParam(StringBuilder sb, object p)
+        {
+            if(p == null)
+            {
+                sb.Append("null");
+            }
+            else if(p is LSL_List)
+            {
+                sb.Append('[');
+                object[] d = ((LSL_List)p).Data;
+                for(int i = 0; i < d.Length; i++)
+                {
+                    if(i > 0)
+                        sb.Append(',');
+                    PrintParam(sb, d[i]);
+                }
+                sb.Append(']');
+            }
+            else if(p is LSL_Rotation)
+            {
+                LSL_Rotation r = (LSL_Rotation)p;
+                sb.Append('<');
+                sb.Append(r.x);
+                sb.Append(',');
+                sb.Append(r.y);
+                sb.Append(',');
+                sb.Append(r.z);
+                sb.Append(',');
+                sb.Append(r.s);
+                sb.Append('>');
+            }
+            else if(p is LSL_String)
+            {
+                PrintParamString(sb, (string)(LSL_String)p);
+            }
+            else if(p is LSL_Vector)
+            {
+                LSL_Vector v = (LSL_Vector)p;
+                sb.Append('<');
+                sb.Append(v.x);
+                sb.Append(',');
+                sb.Append(v.y);
+                sb.Append(',');
+                sb.Append(v.z);
+                sb.Append('>');
+            }
+            else if(p is string)
+            {
+                PrintParamString(sb, (string)p);
+            }
+            else
+            {
+                sb.Append(p.ToString());
+            }
+        }
+
+        public static void PrintParamString(StringBuilder sb, string p)
+        {
+            sb.Append('"');
+            foreach(char c in p)
+            {
+                if(c == '\b')
+                {
+                    sb.Append("\\b");
+                    continue;
+                }
+                if(c == '\n')
+                {
+                    sb.Append("\\n");
+                    continue;
+                }
+                if(c == '\r')
+                {
+                    sb.Append("\\r");
+                    continue;
+                }
+                if(c == '\t')
+                {
+                    sb.Append("\\t");
+                    continue;
+                }
+                if(c == '"')
+                {
+                    sb.Append("\\\"");
+                    continue;
+                }
+                if(c == '\\')
+                {
+                    sb.Append("\\\\");
+                    continue;
+                }
+                sb.Append(c);
+            }
+            sb.Append('"');
+        }
+    }
+
+    /**
+     * @brief Code generators...
+     * @param scg = script we are generating code for
+     * @param result = type/location for result (type matches function definition)
+     * @param args = type/location of arguments (types match function definition)
+     */
+
+    public class TokenDeclInline_LLAbs: TokenDeclInline
+    {
+        public TokenDeclInline_LLAbs(VarDict ifd)
+                : base(ifd, false, "llAbs(integer)", new TokenTypeInt(null)) { }
+
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel("llAbstemp");
+
+            args[0].PushVal(scg, errorAt);
+            scg.ilGen.Emit(errorAt, OpCodes.Dup);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Bge_S, itsPosLabel);
+            scg.ilGen.Emit(errorAt, OpCodes.Neg);
+            scg.ilGen.MarkLabel(itsPosLabel);
+            result.Pop(scg, errorAt, retType);
+        }
+    }
+
+    public class TokenDeclInline_Math: TokenDeclInline
+    {
+        private MethodInfo methInfo;
+
+        public TokenDeclInline_Math(VarDict ifd, string sig, string name, Type[] args)
+                : base(ifd, false, sig, new TokenTypeFloat(null))
+        {
+            methInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), name, args);
+        }
+
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            for(int i = 0; i < args.Length; i++)
+            {
+                args[i].PushVal(scg, errorAt, argDecl.types[i]);
+            }
+            scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
+            result.Pop(scg, errorAt, retType);
+        }
+    }
+
+    public class TokenDeclInline_LLRound: TokenDeclInline
+    {
+
+        private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), "Round",
+                new Type[] { typeof(double), typeof(MidpointRounding) });
+
+        public TokenDeclInline_LLRound(VarDict ifd)
+                : base(ifd, false, "llRound(float)", new TokenTypeInt(null)) { }
+
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            args[0].PushVal(scg, errorAt, new TokenTypeFloat(null));
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero);
+            scg.ilGen.Emit(errorAt, OpCodes.Call, roundMethInfo);
+            result.Pop(scg, errorAt, new TokenTypeFloat(null));
+        }
+    }
+
+    public class TokenDeclInline_GetFreeMemory: TokenDeclInline
+    {
+        private static readonly MethodInfo getFreeMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapLeft", new Type[] { });
+
+        public TokenDeclInline_GetFreeMemory(VarDict ifd)
+                : base(ifd, false, "llGetFreeMemory()", new TokenTypeInt(null)) { }
+
+        // appears as llGetFreeMemory() in script source code
+        // but actually calls xmrHeapLeft()
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            scg.PushXMRInst();
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getFreeMemMethInfo);
+            result.Pop(scg, errorAt, new TokenTypeInt(null));
+        }
+    }
+
+    public class TokenDeclInline_GetUsedMemory: TokenDeclInline
+    {
+        private static readonly MethodInfo getUsedMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapUsed", new Type[] { });
+
+        public TokenDeclInline_GetUsedMemory(VarDict ifd)
+                : base(ifd, false, "llGetUsedMemory()", new TokenTypeInt(null)) { }
+
+        // appears as llGetUsedMemory() in script source code
+        // but actually calls xmrHeapUsed()
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            scg.PushXMRInst();
+            scg.ilGen.Emit(errorAt, OpCodes.Call, getUsedMemMethInfo);
+            result.Pop(scg, errorAt, new TokenTypeInt(null));
+        }
+    }
+
+    /**
+     * @brief Generate code for the usual ll...() functions.
+     */
+    public class TokenDeclInline_BEApi: TokenDeclInline
+    {
+        //        private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod 
+        //                (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) });
+
+        //        private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod 
+        //                (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) });
+
+        public bool doCheckRun;
+        private FieldInfo apiContextField;
+        private MethodInfo methInfo;
+
+        /**
+         * @brief Constructor
+         * @param ifd = dictionary to add the function to
+         * @param dcr = append a call to CheckRun()
+         * @param methInfo = ll...() method to be called
+         */
+        public TokenDeclInline_BEApi(VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf)
+                : base(ifd, dcr, methInfo)
+        {
+            this.methInfo = methInfo;
+            doCheckRun = dcr;
+            apiContextField = acf;
+        }
+
+        public override MethodInfo GetMethodInfo()
+        {
+            return methInfo;
+        }
+
+        /**
+         * @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun().
+         * @param scg    = script being compiled
+         * @param result = where to place result (might be void)
+         * @param args   = script-visible arguments to pass to API function
+         */
+        public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+        {
+            if(isTaggedCallsCheckRun)
+            {                                                   // see if 'xmr' method that calls CheckRun() internally
+                new ScriptCodeGen.CallLabel(scg, errorAt);     // if so, put a call label immediately before it
+                                                               // .. so restoring the frame will jump immediately to the
+                                                               // .. call without re-executing any code before this
+            }
+            if(!methInfo.IsStatic)
+            {
+                scg.PushXMRInst();                          // XMRInstanceSuperType pointer
+                if(apiContextField != null)                 // 'this' pointer for API function
+                    scg.ilGen.Emit(errorAt, OpCodes.Ldfld, apiContextField);
+
+            }
+            for(int i = 0; i < args.Length; i++)             // push arguments, boxing/unboxing as needed
+                args[i].PushVal(scg, errorAt, argDecl.types[i]);
+
+            // this should not be needed
+            //            if (methInfo.Name == "llParcelMediaQuery") {
+            //                scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery);
+            //            }
+            // this should not be needed
+            //            if (methInfo.Name == "llParcelMediaCommandList") {
+            //                scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList);
+            //            }
+            if(methInfo.IsVirtual)                            // call API function
+                scg.ilGen.Emit(errorAt, OpCodes.Callvirt, methInfo);
+            else
+                scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
+
+            result.Pop(scg, errorAt, retType);                  // pop result, boxing/unboxing as needed
+            if(isTaggedCallsCheckRun)
+                scg.openCallLabel = null;
+
+            if(doCheckRun)
+                scg.EmitCallCheckRun(errorAt, false);       // maybe call CheckRun()
+        }
+    }
+}

+ 29 - 24
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptMyILGen.cs → OpenSim/Region/ScriptEngine/YEngine/MMRScriptMyILGen.cs

@@ -29,37 +29,41 @@ using System;
 using System.Reflection;
 using System.Reflection.Emit;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public interface ScriptMyILGen
     {
-        string methName { get; }
-        ScriptMyLocal DeclareLocal (Type type, string name);
-        ScriptMyLabel DefineLabel (string name);
-        void BeginExceptionBlock ();
-        void BeginCatchBlock (Type excType);
-        void BeginFinallyBlock ();
-        void EndExceptionBlock ();
-        void Emit (Token errorAt, OpCode opcode);
-        void Emit (Token errorAt, OpCode opcode, FieldInfo field);
-        void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal);
-        void Emit (Token errorAt, OpCode opcode, Type type);
-        void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel);
-        void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels);
-        void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method);
-        void Emit (Token errorAt, OpCode opcode, MethodInfo method);
-        void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor);
-        void Emit (Token errorAt, OpCode opcode, double value);
-        void Emit (Token errorAt, OpCode opcode, float value);
-        void Emit (Token errorAt, OpCode opcode, int value);
-        void Emit (Token errorAt, OpCode opcode, string value);
-        void MarkLabel (ScriptMyLabel myLabel);
+        string methName
+        {
+            get;
+        }
+        ScriptMyLocal DeclareLocal(Type type, string name);
+        ScriptMyLabel DefineLabel(string name);
+        void BeginExceptionBlock();
+        void BeginCatchBlock(Type excType);
+        void BeginFinallyBlock();
+        void EndExceptionBlock();
+        void Emit(Token errorAt, OpCode opcode);
+        void Emit(Token errorAt, OpCode opcode, FieldInfo field);
+        void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal);
+        void Emit(Token errorAt, OpCode opcode, Type type);
+        void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel);
+        void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels);
+        void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method);
+        void Emit(Token errorAt, OpCode opcode, MethodInfo method);
+        void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor);
+        void Emit(Token errorAt, OpCode opcode, double value);
+        void Emit(Token errorAt, OpCode opcode, float value);
+        void Emit(Token errorAt, OpCode opcode, int value);
+        void Emit(Token errorAt, OpCode opcode, string value);
+        void MarkLabel(ScriptMyLabel myLabel);
     }
 
     /**
      * @brief One of these per label defined in the function.
      */
-    public class ScriptMyLabel {
+    public class ScriptMyLabel
+    {
         public string name;
         public int number;
 
@@ -71,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
     /**
      * @brief One of these per local variable defined in the function.
      */
-    public class ScriptMyLocal {
+    public class ScriptMyLocal
+    {
         public string name;
         public Type type;
         public int number;

+ 245 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptObjCode.cs

@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Yengine;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public delegate void ScriptEventHandler(XMRInstAbstract instance);
+
+    /*
+     * This object represents the output of the compilation.
+     * Once the compilation is complete, its contents should be
+     * considered 'read-only', so it can be shared among multiple
+     * instances of the script.
+     *
+     * It gets created by ScriptCodeGen.
+     * It gets used by XMRInstance to create script instances.
+     */
+    public class ScriptObjCode
+    {
+        public string sourceHash;         // source text hash code
+        public XMRInstArSizes glblSizes = new XMRInstArSizes();
+        // number of global variables of various types
+
+        public string[] stateNames;       // convert state number to corresponding string
+        public ScriptEventHandler[,] scriptEventHandlerTable;
+        // entrypoints to all event handler functions
+        // 1st subscript = state code number (0=default)
+        // 2nd subscript = event code number
+        // null entry means no handler defined for that state,event
+
+        public Dictionary<string, TokenDeclSDType> sdObjTypesName;
+        // all script-defined types by name
+
+        public TokenDeclSDType[] sdObjTypesIndx;
+        // all script-defined types by sdTypeIndex
+
+        public Dictionary<Type, string> sdDelTypes;
+        // all script-defined delegates (including anonymous)
+
+        public Dictionary<string, DynamicMethod> dynamicMethods;
+        // all dyanmic methods
+
+        public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
+        // method,iloffset -> source file,line,posn
+
+        public int refCount;              // used by engine to keep track of number of 
+                                          // instances that are using this object code
+
+        public Dictionary<string, Dictionary<int, string>> globalVarNames = new Dictionary<string, Dictionary<int, string>>();
+
+        /**
+         * @brief Fill in ScriptObjCode from an YEngine object file.
+         *   'objFileReader' is a serialized form of the CIL code we generated
+         *   'asmFileWriter' is where we write the disassembly to (or null if not wanted)
+         *   'srcFileWriter' is where we write the decompilation to (or null if not wanted)
+         * Throws an exception if there is any error (theoretically).
+         */
+        public ScriptObjCode(BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
+        {
+            /*
+             * Check version number to make sure we know how to process file contents.
+             */
+            char[] ocm = objFileReader.ReadChars(ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
+            if(new String(ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC)
+                throw new Exception("not an XMR object file (bad magic)");
+
+            int cvv = objFileReader.ReadInt32();
+            if(cvv != ScriptCodeGen.COMPILED_VERSION_VALUE)
+                throw new CVVMismatchException(cvv, ScriptCodeGen.COMPILED_VERSION_VALUE);
+
+            // Fill in simple parts of scriptObjCode object.
+            sourceHash = objFileReader.ReadString();
+            glblSizes.ReadFromFile(objFileReader);
+            int nStates = objFileReader.ReadInt32();
+
+            stateNames = new string[nStates];
+            for(int i = 0; i < nStates; i++)
+            {
+                stateNames[i] = objFileReader.ReadString();
+                if(asmFileWriter != null)
+                    asmFileWriter.WriteLine("  state[{0}] = {1}", i, stateNames[i]);
+            }
+
+            if(asmFileWriter != null)
+                glblSizes.WriteAsmFile(asmFileWriter, "numGbl");
+
+            string gblName;
+            while((gblName = objFileReader.ReadString()) != "")
+            {
+                string gblType = objFileReader.ReadString();
+                int gblIndex = objFileReader.ReadInt32();
+                Dictionary<int, string> names;
+                if(!globalVarNames.TryGetValue(gblType, out names))
+                {
+                    names = new Dictionary<int, string>();
+                    globalVarNames.Add(gblType, names);
+                }
+                names.Add(gblIndex, gblName);
+                if(asmFileWriter != null)
+                    asmFileWriter.WriteLine("  {0} = {1}[{2}]", gblName, gblType, gblIndex);
+            }
+
+            // Read in script-defined types.
+            sdObjTypesName = new Dictionary<string, TokenDeclSDType>();
+            sdDelTypes = new Dictionary<Type, string>();
+            int maxIndex = -1;
+            while((gblName = objFileReader.ReadString()) != "")
+            {
+                TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile(sdObjTypesName,
+                                                      gblName, objFileReader, asmFileWriter);
+                sdObjTypesName.Add(gblName, sdt);
+                if(maxIndex < sdt.sdTypeIndex)
+                    maxIndex = sdt.sdTypeIndex;
+                if(sdt is TokenDeclSDTypeDelegate)
+                    sdDelTypes.Add(sdt.GetSysType(), gblName);
+            }
+            sdObjTypesIndx = new TokenDeclSDType[maxIndex + 1];
+            foreach(TokenDeclSDType sdt in sdObjTypesName.Values)
+                sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
+
+            // Now fill in the methods (the hard part).
+            scriptEventHandlerTable = new ScriptEventHandler[nStates, (int)ScriptEventCode.Size];
+            dynamicMethods = new Dictionary<string, DynamicMethod>();
+            scriptSrcLocss = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]>();
+
+            ObjectTokens objectTokens = null;
+            if(asmFileWriter != null)
+                objectTokens = new OTDisassemble(this, asmFileWriter);
+            else if(srcFileWriter != null)
+                objectTokens = new OTDecompile(this, srcFileWriter);
+
+            try
+            {
+                ScriptObjWriter.CreateObjCode(sdObjTypesName, objFileReader, this, objectTokens);
+            }
+            finally
+            {
+                if(objectTokens != null)
+                    objectTokens.Close();
+            }
+
+            // We enter all script event handler methods in the ScriptEventHandler table.
+            // They are named:  <statename> <eventname>
+            foreach(KeyValuePair<string, DynamicMethod> kvp in dynamicMethods)
+            {
+                string methName = kvp.Key;
+                int i = methName.IndexOf(' ');
+                if(i < 0)
+                    continue;
+                string stateName = methName.Substring(0, i);
+                string eventName = methName.Substring(++i);
+                int stateCode;
+                for(stateCode = stateNames.Length; --stateCode >= 0;)
+                    if(stateNames[stateCode] == stateName)
+                        break;
+
+                int eventCode = (int)Enum.Parse(typeof(ScriptEventCode), eventName);
+                scriptEventHandlerTable[stateCode, eventCode] =
+                            (ScriptEventHandler)kvp.Value.CreateDelegate(typeof(ScriptEventHandler));
+            }
+
+            // Fill in all script-defined class vtables.
+            foreach(TokenDeclSDType sdt in sdObjTypesIndx)
+            {
+                if((sdt != null) && (sdt is TokenDeclSDTypeClass))
+                {
+                    TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
+                    sdtc.FillVTables(this);
+                }
+            }
+        }
+
+        /**
+         * @brief Called once for every method found in objFileReader file.
+         *        It enters the method in the ScriptObjCode object table so it can be called.
+         */
+        public void EndMethod(DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
+        {
+            /*
+             * Save method object code pointer.
+             */
+            dynamicMethods.Add(method.Name, method);
+
+            /*
+             * Build and sort iloffset -> source code location array.
+             */
+            int n = srcLocs.Count;
+            KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
+            n = 0;
+            foreach(KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs)
+                srcLocArray[n++] = kvp;
+            Array.Sort(srcLocArray, endMethodWrapper);
+
+            /*
+             * Save sorted array.
+             */
+            scriptSrcLocss.Add(method.Name, srcLocArray);
+        }
+
+        /**
+         * @brief Called once for every method found in objFileReader file.
+         *        It enters the method in the ScriptObjCode object table so it can be called.
+         */
+        private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper();
+        private class EndMethodWrapper: System.Collections.IComparer
+        {
+            public int Compare(object x, object y)
+            {
+                KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
+                KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
+                return kvpx.Key - kvpy.Key;
+            }
+        }
+    }
+}

+ 1040 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptObjWriter.cs

@@ -0,0 +1,1040 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * @brief Wrapper class for ILGenerator.
+ *        It writes the object code to a file and can then make real ILGenerator calls
+ *        based on the file's contents.
+ */
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public enum ScriptObjWriterCode: byte
+    {
+        BegMethod, EndMethod, TheEnd,
+        DclLabel, DclLocal, DclMethod, MarkLabel,
+        EmitNull, EmitField, EmitLocal, EmitType, EmitLabel, EmitMethodExt,
+        EmitMethodInt, EmitCtor, EmitDouble, EmitFloat, EmitInteger, EmitString,
+        EmitLabels,
+        BegExcBlk, BegCatBlk, BegFinBlk, EndExcBlk
+    }
+
+    public class ScriptObjWriter: ScriptMyILGen
+    {
+        private static Dictionary<short, OpCode> opCodes = PopulateOpCodes();
+        private static Dictionary<string, Type> string2Type = PopulateS2T();
+        private static Dictionary<Type, string> type2String = PopulateT2S();
+
+        private static MethodInfo monoGetCurrentOffset = typeof(ILGenerator).GetMethod("Mono_GetCurrentOffset",
+                        BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null,
+                        new Type[] { typeof(ILGenerator) }, null);
+
+        private static readonly OpCode[] opCodesLdcI4M1P8 = new OpCode[] {
+            OpCodes.Ldc_I4_M1, OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3,
+            OpCodes.Ldc_I4_4,  OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8
+        };
+
+        private BinaryWriter objFileWriter;
+        private string lastErrorAtFile = "";
+        private int lastErrorAtLine = 0;
+        private int lastErrorAtPosn = 0;
+
+        private Dictionary<Type, string> sdTypesRev = new Dictionary<Type, string>();
+        public int labelNumber = 0;
+        public int localNumber = 0;
+
+        private string _methName;
+        public string methName
+        {
+            get
+            {
+                return _methName;
+            }
+        }
+
+        public Type retType;
+        public Type[] argTypes;
+
+        /**
+         * @brief Begin function declaration
+         * @param sdTypes    = script-defined types
+         * @param methName   = name of the method being declared, eg, "Verify(array,list,string)"
+         * @param retType    = its return value type
+         * @param argTypes[] = its argument types
+         * @param objFileWriter  = file to write its object code to
+         *
+         * After calling this function, the following functions should be called:
+         *    this.BegMethod ();
+         *      this.<as required> ();
+         *    this.EndMethod ();
+         *
+         * The design of this object is such that many constructors may be called,
+         * but once a BegMethod() is called for one of the objects, no method may
+         * called for any of the other objects until EndMethod() is called (or it 
+         * would break up the object stream for that method).  But we need to have
+         * many constructors possible so we get function headers at the beginning
+         * of the object file in case there are forward references to the functions.
+         */
+        public ScriptObjWriter(TokenScript tokenScript, string methName, Type retType, Type[] argTypes, string[] argNames, BinaryWriter objFileWriter)
+        {
+            this._methName = methName;
+            this.retType = retType;
+            this.argTypes = argTypes;
+            this.objFileWriter = objFileWriter;
+
+            /*
+             * Build list that translates system-defined types to script defined types.
+             */
+            foreach(TokenDeclSDType sdt in tokenScript.sdSrcTypesValues)
+            {
+                Type sys = sdt.GetSysType();
+                if(sys != null)
+                    sdTypesRev[sys] = sdt.longName.val;
+            }
+
+            /*
+             * This tells the reader to call 'new DynamicMethod()' to create
+             * the function header.  Then any forward reference calls to this
+             * method will have a MethodInfo struct to call.
+             */
+            objFileWriter.Write((byte)ScriptObjWriterCode.DclMethod);
+            objFileWriter.Write(methName);
+            objFileWriter.Write(GetStrFromType(retType));
+
+            int nArgs = argTypes.Length;
+            objFileWriter.Write(nArgs);
+            for(int i = 0; i < nArgs; i++)
+            {
+                objFileWriter.Write(GetStrFromType(argTypes[i]));
+                objFileWriter.Write(argNames[i]);
+            }
+        }
+
+        /**
+         * @brief Begin outputting object code for the function
+         */
+        public void BegMethod()
+        {
+            /*
+             * This tells the reader to call methodInfo.GetILGenerator()
+             * so it can start writing CIL code for the method.
+             */
+            objFileWriter.Write((byte)ScriptObjWriterCode.BegMethod);
+            objFileWriter.Write(methName);
+        }
+
+        /**
+         * @brief End of object code for the function
+         */
+        public void EndMethod()
+        {
+            /*
+             * This tells the reader that all code for the method has
+             * been written and so it will typically call CreateDelegate()
+             * to finalize the method and create an entrypoint.
+             */
+            objFileWriter.Write((byte)ScriptObjWriterCode.EndMethod);
+
+            objFileWriter = null;
+        }
+
+        /**
+         * @brief Declare a local variable for use by the function
+         */
+        public ScriptMyLocal DeclareLocal(Type type, string name)
+        {
+            ScriptMyLocal myLocal = new ScriptMyLocal();
+            myLocal.type = type;
+            myLocal.name = name;
+            myLocal.number = localNumber++;
+            myLocal.isReferenced = true;  // so ScriptCollector won't optimize references away
+            return DeclareLocal(myLocal);
+        }
+        public ScriptMyLocal DeclareLocal(ScriptMyLocal myLocal)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.DclLocal);
+            objFileWriter.Write(myLocal.number);
+            objFileWriter.Write(myLocal.name);
+            objFileWriter.Write(GetStrFromType(myLocal.type));
+            return myLocal;
+        }
+
+        /**
+         * @brief Define a label for use by the function
+         */
+        public ScriptMyLabel DefineLabel(string name)
+        {
+            ScriptMyLabel myLabel = new ScriptMyLabel();
+            myLabel.name = name;
+            myLabel.number = labelNumber++;
+            return DefineLabel(myLabel);
+        }
+        public ScriptMyLabel DefineLabel(ScriptMyLabel myLabel)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.DclLabel);
+            objFileWriter.Write(myLabel.number);
+            objFileWriter.Write(myLabel.name);
+            return myLabel;
+        }
+
+        /**
+         * @brief try/catch blocks.
+         */
+        public void BeginExceptionBlock()
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.BegExcBlk);
+        }
+
+        public void BeginCatchBlock(Type excType)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.BegCatBlk);
+            objFileWriter.Write(GetStrFromType(excType));
+        }
+
+        public void BeginFinallyBlock()
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.BegFinBlk);
+        }
+
+        public void EndExceptionBlock()
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EndExcBlk);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitNull);
+            WriteOpCode(errorAt, opcode);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, FieldInfo field)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitField);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(GetStrFromType(field.ReflectedType));
+            objFileWriter.Write(field.Name);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitLocal);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(myLocal.number);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, Type type)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitType);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(GetStrFromType(type));
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitLabel);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(myLabel.number);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitLabels);
+            WriteOpCode(errorAt, opcode);
+            int nLabels = myLabels.Length;
+            objFileWriter.Write(nLabels);
+            for(int i = 0; i < nLabels; i++)
+            {
+                objFileWriter.Write(myLabels[i].number);
+            }
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method)
+        {
+            if(method == null)
+                throw new ArgumentNullException("method");
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitMethodInt);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(method.methName);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, MethodInfo method)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitMethodExt);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(method.Name);
+            objFileWriter.Write(GetStrFromType(method.ReflectedType));
+            ParameterInfo[] parms = method.GetParameters();
+            int nArgs = parms.Length;
+            objFileWriter.Write(nArgs);
+            for(int i = 0; i < nArgs; i++)
+            {
+                objFileWriter.Write(GetStrFromType(parms[i].ParameterType));
+            }
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitCtor);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(GetStrFromType(ctor.ReflectedType));
+            ParameterInfo[] parms = ctor.GetParameters();
+            int nArgs = parms.Length;
+            objFileWriter.Write(nArgs);
+            for(int i = 0; i < nArgs; i++)
+            {
+                objFileWriter.Write(GetStrFromType(parms[i].ParameterType));
+            }
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, double value)
+        {
+            if(opcode != OpCodes.Ldc_R8)
+            {
+                throw new Exception("bad opcode " + opcode.ToString());
+            }
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitDouble);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(value);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, float value)
+        {
+            if(opcode != OpCodes.Ldc_R4)
+            {
+                throw new Exception("bad opcode " + opcode.ToString());
+            }
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitFloat);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(value);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, int value)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitInteger);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(value);
+        }
+
+        public void Emit(Token errorAt, OpCode opcode, string value)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.EmitString);
+            WriteOpCode(errorAt, opcode);
+            objFileWriter.Write(value);
+        }
+
+        /**
+         * @brief Declare that the target of a label is the next instruction.
+         */
+        public void MarkLabel(ScriptMyLabel myLabel)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.MarkLabel);
+            objFileWriter.Write(myLabel.number);
+        }
+
+        /**
+         * @brief Write end-of-file marker to binary file.
+         */
+        public static void TheEnd(BinaryWriter objFileWriter)
+        {
+            objFileWriter.Write((byte)ScriptObjWriterCode.TheEnd);
+        }
+
+        /**
+         * @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());
+                }
+            }
+        }
+
+        /**
+         * @brief Generate array to quickly translate OpCode.Value to full OpCode struct.
+         */
+        private static Dictionary<short, OpCode> PopulateOpCodes()
+        {
+            Dictionary<short, OpCode> opCodeDict = new Dictionary<short, OpCode>();
+            FieldInfo[] fields = typeof(OpCodes).GetFields();
+            for(int i = 0; i < fields.Length; i++)
+            {
+                OpCode opcode = (OpCode)fields[i].GetValue(null);
+                opCodeDict.Add(opcode.Value, opcode);
+            }
+            return opCodeDict;
+        }
+
+        /**
+         * @brief Write opcode out to file.
+         */
+        private void WriteOpCode(Token errorAt, OpCode opcode)
+        {
+            if(errorAt == null)
+            {
+                objFileWriter.Write("");
+                objFileWriter.Write(lastErrorAtLine);
+                objFileWriter.Write(lastErrorAtPosn);
+            }
+            else
+            {
+                if(errorAt.file != lastErrorAtFile)
+                {
+                    objFileWriter.Write(errorAt.file);
+                    lastErrorAtFile = errorAt.file;
+                }
+                else
+                {
+                    objFileWriter.Write("");
+                }
+                objFileWriter.Write(errorAt.line);
+                objFileWriter.Write(errorAt.posn);
+                lastErrorAtLine = errorAt.line;
+                lastErrorAtPosn = errorAt.posn;
+            }
+            objFileWriter.Write(opcode.Value);
+        }
+
+        /**
+         * @brief Read opcode in from file.
+         */
+        private static OpCode ReadOpCode(BinaryReader objReader, ref string srcFile, ref int srcLine, ref int srcPosn)
+        {
+            string f = objReader.ReadString();
+            if(f != "")
+                srcFile = f;
+            srcLine = objReader.ReadInt32();
+            srcPosn = objReader.ReadInt32();
+
+            short value = objReader.ReadInt16();
+            return opCodes[value];
+        }
+
+        /**
+         * @brief Save an IL_offset -> source location translation entry
+         * @param srcLocs = saved entries for the current function
+         * @param offset = offset in IL object code for next instruction
+         * @param src{File,Line,Posn} = location in source file corresponding to opcode
+         * @returns with entry added to srcLocs
+         */
+        private static void SaveSrcLoc(Dictionary<int, ScriptSrcLoc> srcLocs, int offset, string srcFile, int srcLine, int srcPosn)
+        {
+            ScriptSrcLoc srcLoc = new ScriptSrcLoc();
+            srcLoc.file = srcFile;
+            srcLoc.line = srcLine;
+            srcLoc.posn = srcPosn;
+            srcLocs[offset] = srcLoc;
+        }
+
+        /**
+         * @brief Create type<->string conversions.
+         *        Using Type.AssemblyQualifiedName is horribly inefficient
+         *        and all our types should be known.
+         */
+        private static Dictionary<string, Type> PopulateS2T()
+        {
+            Dictionary<string, Type> s2t = new Dictionary<string, Type>();
+
+            s2t.Add("badcallx", typeof(ScriptBadCallNoException));
+            s2t.Add("binopstr", typeof(BinOpStr));
+            s2t.Add("bool", typeof(bool));
+            s2t.Add("char", typeof(char));
+            s2t.Add("delegate", typeof(Delegate));
+            s2t.Add("delarr[]", typeof(Delegate[]));
+            s2t.Add("double", typeof(double));
+            s2t.Add("exceptn", typeof(Exception));
+            s2t.Add("float", typeof(float));
+            s2t.Add("htlist", typeof(HeapTrackerList));
+            s2t.Add("htobject", typeof(HeapTrackerObject));
+            s2t.Add("htstring", typeof(HeapTrackerString));
+            s2t.Add("inlfunc", typeof(CompValuInline));
+            s2t.Add("int", typeof(int));
+            s2t.Add("int*", typeof(int).MakeByRefType());
+            s2t.Add("intrlokd", typeof(System.Threading.Interlocked));
+            s2t.Add("lslfloat", typeof(LSL_Float));
+            s2t.Add("lslint", typeof(LSL_Integer));
+            s2t.Add("lsllist", typeof(LSL_List));
+            s2t.Add("lslrot", typeof(LSL_Rotation));
+            s2t.Add("lslstr", typeof(LSL_String));
+            s2t.Add("lslvec", typeof(LSL_Vector));
+            s2t.Add("math", typeof(Math));
+            s2t.Add("midround", typeof(MidpointRounding));
+            s2t.Add("object", typeof(object));
+            s2t.Add("object*", typeof(object).MakeByRefType());
+            s2t.Add("object[]", typeof(object[]));
+            s2t.Add("scrbase", typeof(ScriptBaseClass));
+            s2t.Add("scrcode", typeof(ScriptCodeGen));
+            s2t.Add("sdtclobj", typeof(XMRSDTypeClObj));
+            s2t.Add("string", typeof(string));
+            s2t.Add("typecast", typeof(TypeCast));
+            s2t.Add("undstatx", typeof(ScriptUndefinedStateException));
+            s2t.Add("void", typeof(void));
+            s2t.Add("xmrarray", typeof(XMR_Array));
+            s2t.Add("xmrinst", typeof(XMRInstAbstract));
+
+            return s2t;
+        }
+
+        private static Dictionary<Type, string> PopulateT2S()
+        {
+            Dictionary<string, Type> s2t = PopulateS2T();
+            Dictionary<Type, string> t2s = new Dictionary<Type, string>();
+            foreach(KeyValuePair<string, Type> kvp in s2t)
+            {
+                t2s.Add(kvp.Value, kvp.Key);
+            }
+            return t2s;
+        }
+
+        /**
+         * @brief Add to list of internally recognized types.
+         */
+        public static void DefineInternalType(string name, Type type)
+        {
+            if(!string2Type.ContainsKey(name))
+            {
+                string2Type.Add(name, type);
+                type2String.Add(type, name);
+            }
+        }
+
+        private string GetStrFromType(Type t)
+        {
+            string s = GetStrFromTypeWork(t);
+            return s;
+        }
+        private string GetStrFromTypeWork(Type t)
+        {
+            string s;
+
+            // internal fixed types like int and xmrarray etc
+            if(type2String.TryGetValue(t, out s))
+                return s;
+
+            // script-defined types
+            if(sdTypesRev.TryGetValue(t, out s))
+                return "sdt$" + s;
+
+            // inline function types
+            s = TokenDeclSDTypeDelegate.TryGetInlineName(t);
+            if(s != null)
+                return s;
+
+            // last resort
+            return t.AssemblyQualifiedName;
+        }
+
+        private static Type GetTypeFromStr(Dictionary<string, TokenDeclSDType> sdTypes, string s)
+        {
+            Type t;
+
+            // internal fixed types like int and xmrarray etc
+            if(string2Type.TryGetValue(s, out t))
+                return t;
+
+            // script-defined types
+            if(s.StartsWith("sdt$"))
+                return sdTypes[s.Substring(4)].GetSysType();
+
+            // inline function types
+            t = TokenDeclSDTypeDelegate.TryGetInlineSysType(s);
+            if(t != null)
+                return t;
+
+            // last resort
+            return Type.GetType(s, true);
+        }
+    }
+
+    public class ScriptSrcLoc
+    {
+        public string file;
+        public int line;
+        public int posn;
+    }
+}

File diff suppressed because it is too large
+ 325 - 248
OpenSim/Region/ScriptEngine/YEngine/MMRScriptReduce.cs


+ 2972 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptTokenize.cs

@@ -0,0 +1,2972 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @brief Parse raw source file string into token list.
+ *
+ * Usage:
+ *
+ *    emsg = some function to output error messages to
+ *    source = string containing entire source file
+ *
+ *    TokenBegin tokenBegin = TokenBegin.Construct (emsg, source);
+ *
+ *    tokenBegin = null: tokenizing error
+ *                 else: first (dummy) token in file
+ *                       the rest are chained by nextToken,prevToken
+ *                       final token is always a (dummy) TokenEnd
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    public delegate void TokenErrorMessage(Token token, string message);
+
+    /**
+     * @brief base class for all tokens
+     */
+    public class Token
+    {
+        public static readonly int MAX_NAME_LEN = 255;
+        public static readonly int MAX_STRING_LEN = 4096;
+
+        public Token nextToken;
+        public Token prevToken;
+        public bool nr2l;
+
+        // used for error message printing
+        public TokenErrorMessage emsg;
+        public string file = "";
+        public int line;
+        public int posn;
+        public Token copiedFrom;
+
+        /**
+         * @brief construct a token coming directly from a source file
+         * @param emsg = object that error messages get sent to
+         * @param file = source file name (or "" if none)
+         * @param line = source file line number
+         * @param posn = token's position within that source line
+         */
+        public Token(TokenErrorMessage emsg, string file, int line, int posn)
+        {
+            this.emsg = emsg;
+            this.file = file;
+            this.line = line;
+            this.posn = posn;
+        }
+
+        /**
+         * @brief construct a token with same error message parameters
+         * @param original = original token to create from
+         */
+        public Token(Token original)
+        {
+            if(original != null)
+            {
+                this.emsg = original.emsg;
+                this.file = original.file;
+                this.line = original.line;
+                this.posn = original.posn;
+                this.nr2l = original.nr2l;
+            }
+        }
+
+        /**
+         * @brief output an error message associated with this token
+         *        sends the message to the token's error object
+         * @param message = error message string
+         */
+        public void ErrorMsg(string message)
+        {
+            if(emsg != null)
+            {
+                emsg(this, message);
+            }
+        }
+
+        /*
+         * Generate a unique string (for use in CIL label names, etc)
+         */
+        public string Unique
+        {
+            get
+            {
+                return file + "_" + line + "_" + posn;
+            }
+        }
+
+        /*
+         * Generate source location string (for use in error messages)
+         */
+        public string SrcLoc
+        {
+            get
+            {
+                string loc = file + "(" + line + "," + posn + ")";
+                if(copiedFrom == null)
+                    return loc;
+                string fromLoc = copiedFrom.SrcLoc;
+                if(fromLoc.StartsWith(loc))
+                    return fromLoc;
+                return loc + ":" + fromLoc;
+            }
+        }
+
+        /*
+         * Used in generic instantiation to copy token.
+         * Only valid for parsing tokens, not reduction tokens 
+         * because it is a shallow copy.
+         */
+        public Token CopyToken(Token src)
+        {
+            Token t = (Token)this.MemberwiseClone();
+            t.file = src.file;
+            t.line = src.line;
+            t.posn = src.posn;
+            t.copiedFrom = this;
+            return t;
+        }
+
+        /*
+         * Generate debugging string - should look like source code.
+         */
+        public virtual void DebString(StringBuilder sb)
+        {
+            sb.Append(this.ToString());
+        }
+    }
+
+
+    /**
+     * @brief token that begins a source file
+     *        Along with TokenEnd, it keeps insertion/removal of intermediate tokens
+     *        simple as the intermediate tokens always have non-null nextToken,prevToken.
+     */
+    public class TokenBegin: Token
+    {
+        private class Options
+        {
+            public bool arrays;         // has seen 'XMROption arrays;'
+            public bool advFlowCtl;     // has seen 'XMROption advFlowCtl;'
+            public bool tryCatch;       // has seen 'XMROption tryCatch;'
+            public bool objects;        // has seen 'XMROption objects;'
+            public bool chars;          // has seen 'XMROption chars;'
+            public bool noRightToLeft;  // has seen 'XMROption noRightToLeft;'
+            public bool dollarsigns;    // has seen 'XMROption dollarsigns;'
+        }
+
+        private bool youveAnError;      // there was some error tokenizing
+        private int bolIdx;             // index in 'source' at begining of current line
+        private int lineNo;             // current line in source file, starting at 0
+        private string filNam;          // current source file name
+        private string source;          // the whole script source code
+        private Token lastToken;        // last token created so far
+        private string cameFrom;        // where the source came from
+        private TextWriter saveSource;  // save copy of source here (or null)
+        private Options options = new Options();
+
+        /**
+         * @brief convert a source file in the form of a string
+         *        to a list of raw tokens
+         * @param cameFrom = where the source came from
+         * @param emsg     = where to output messages to
+         * @param source   = whole source file contents
+         * @returns null: conversion error, message already output
+         *          else: list of tokens, starting with TokenBegin, ending with TokenEnd.
+         */
+        public static TokenBegin Construct(string cameFrom, TextWriter saveSource, TokenErrorMessage emsg, string source, out string sourceHash)
+        {
+            sourceHash = null;
+
+            /*
+             * Now do the tokenization.
+             */
+            TokenBegin tokenBegin = new TokenBegin(emsg, "", 0, 0);
+            tokenBegin.cameFrom = cameFrom;
+            tokenBegin.saveSource = saveSource;
+            tokenBegin.lastToken = tokenBegin;
+            tokenBegin.source = source;
+            tokenBegin.filNam = cameFrom;
+            if(saveSource != null)
+                saveSource.WriteLine(source);
+            tokenBegin.Tokenize();
+            if(tokenBegin.youveAnError)
+                return null;
+            tokenBegin.AppendToken(new TokenEnd(emsg, tokenBegin.filNam, ++tokenBegin.lineNo, 0));
+
+            /*
+             * Return source hash so caller can know if source changes.
+             */
+            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
+            byte[] hashBytes = md5.ComputeHash(new TokenStream(tokenBegin));
+            int hashBytesLen = hashBytes.Length;
+            StringBuilder sb = new StringBuilder(hashBytesLen * 2);
+            for(int i = 0; i < hashBytesLen; i++)
+            {
+                sb.Append(hashBytes[i].ToString("X2"));
+            }
+            sourceHash = sb.ToString();
+            if(saveSource != null)
+            {
+                saveSource.WriteLine("");
+                saveSource.WriteLine("********************************************************************************");
+                saveSource.WriteLine("****  source hash: " + sourceHash);
+                saveSource.WriteLine("********************************************************************************");
+            }
+
+            return tokenBegin;
+        }
+
+        private TokenBegin(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+
+        /*
+         * Stream consisting of all the tokens.
+         * Null delimeters between the tokens.
+         * Used for creating the source hash.
+         */
+        private class TokenStream: Stream
+        {
+            private Token curTok;
+            private bool delim;
+            private byte[] curBuf;
+            private int curOfs;
+            private int curLen;
+
+            public TokenStream(Token t)
+            {
+                curTok = t;
+            }
+
+            public override bool CanRead
+            {
+                get
+                {
+                    return true;
+                }
+            }
+            public override bool CanSeek
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool CanWrite
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override long Length
+            {
+                get
+                {
+                    return 0;
+                }
+            }
+            public override long Position
+            {
+                get
+                {
+                    return 0;
+                }
+                set
+                {
+                }
+            }
+
+            public override void Write(byte[] buffer, int offset, int count)
+            {
+            }
+            public override void Flush()
+            {
+            }
+            public override long Seek(long offset, SeekOrigin origin)
+            {
+                return 0;
+            }
+            public override void SetLength(long value)
+            {
+            }
+
+            public override int Read(byte[] buffer, int offset, int count)
+            {
+                int len, total;
+                for(total = 0; total < count; total += len)
+                {
+                    while((len = curLen - curOfs) <= 0)
+                    {
+                        if(curTok is TokenEnd)
+                            goto done;
+                        curTok = curTok.nextToken;
+                        if(curTok is TokenEnd)
+                            goto done;
+                        curBuf = System.Text.Encoding.UTF8.GetBytes(curTok.ToString());
+                        curOfs = 0;
+                        curLen = curBuf.Length;
+                        delim = true;
+                    }
+                    if(delim)
+                    {
+                        buffer[offset + total] = 0;
+                        delim = false;
+                        len = 1;
+                    }
+                    else
+                    {
+                        if(len > count - total)
+                            len = count - total;
+                        Array.Copy(curBuf, curOfs, buffer, offset + total, len);
+                        curOfs += len;
+                    }
+                }
+                done:
+                return total;
+            }
+        }
+
+        /*
+         * Produces raw token stream: names, numbers, strings, keywords/delimeters.
+         * @param this.source = whole source file in one string
+         * @returns this.nextToken = filled in with tokens
+         *          this.youveAnError = true: some tokenizing error
+         *                             false: successful
+         */
+        private void Tokenize()
+        {
+            bolIdx = 0;
+            lineNo = 0;
+            for(int i = 0; i < source.Length; i++)
+            {
+                char c = source[i];
+                if(c == '\n')
+                {
+
+                    /*
+                     * Increment source line number and set char index of beg of next line.
+                     */
+                    lineNo++;
+                    bolIdx = i + 1;
+
+                    /*
+                     * Check for '#' lineno filename newline
+                     * lineno is line number of next line in file
+                     * If found, save values and remove tokens from stream
+                     */
+                    if((lastToken is TokenStr) &&
+                        (lastToken.prevToken is TokenInt) &&
+                        (lastToken.prevToken.prevToken is TokenKwHash))
+                    {
+                        filNam = ((TokenStr)lastToken).val;
+                        lineNo = ((TokenInt)lastToken.prevToken).val;
+                        lastToken = lastToken.prevToken.prevToken.prevToken;
+                        lastToken.nextToken = null;
+                    }
+                    continue;
+                }
+
+                /*
+                 * Skip over whitespace.
+                 */
+                if(c <= ' ')
+                    continue;
+
+                /*
+                 * Skip over comments.
+                 */
+                if((i + 2 <= source.Length) && source.Substring(i, 2).Equals("//"))
+                {
+                    while((i < source.Length) && (source[i] != '\n'))
+                        i++;
+                    lineNo++;
+                    bolIdx = i + 1;
+                    continue;
+                }
+                if((i + 2 <= source.Length) && (source.Substring(i, 2).Equals("/*")))
+                {
+                    i += 2;
+                    while((i + 1 < source.Length) && (((c = source[i]) != '*') || (source[i + 1] != '/')))
+                    {
+                        if(c == '\n')
+                        {
+                            lineNo++;
+                            bolIdx = i + 1;
+                        }
+                        i++;
+                    }
+                    i++;
+                    continue;
+                }
+
+                /*
+                 * Check for numbers.
+                 */
+                if((c >= '0') && (c <= '9'))
+                {
+                    int j = TryParseFloat(i);
+                    if(j == 0)
+                        j = TryParseInt(i);
+                    i = --j;
+                    continue;
+                }
+                if((c == '.') && (i + 1 < source.Length) && (source[i + 1] >= '0') && (source[i + 1] <= '9'))
+                {
+                    int j = TryParseFloat(i);
+                    if(j > 0)
+                        i = --j;
+                    continue;
+                }
+
+                /*
+                 * Check for quoted strings.
+                 */
+                if(c == '"')
+                {
+                    StringBuilder sb = new StringBuilder();
+                    bool backslash;
+                    int j;
+
+                    backslash = false;
+                    for(j = i; ++j < source.Length;)
+                    {
+                        c = source[j];
+                        if(c == '\\' && !backslash)
+                        {
+                            backslash = true;
+                            continue;
+                        }
+                        if(c == '\n')
+                        {
+                            lineNo++;
+                            bolIdx = j + 1;
+                        }
+                        else
+                        {
+                            if(!backslash && (c == '"'))
+                                break;
+                            if(backslash && (c == 'n'))
+                                c = '\n';
+                            if(backslash && (c == 't'))
+                            {
+                                sb.Append("   ");
+                                c = ' ';
+                            }
+                        }
+                        backslash = false;
+                        sb.Append(c);
+                    }
+                    if(j - i > MAX_STRING_LEN)
+                    {
+                        TokenError(i, "string too long, max " + MAX_STRING_LEN);
+                    }
+                    else
+                    {
+                        AppendToken(new TokenStr(emsg, filNam, lineNo, i - bolIdx, sb.ToString()));
+                    }
+                    i = j;
+                    continue;
+                }
+
+                /*
+                 * Check for quoted characters.
+                 */
+                if(c == '\'')
+                {
+                    char cb = (char)0;
+                    bool backslash, overflow, underflow;
+                    int j;
+
+                    backslash = false;
+                    overflow = false;
+                    underflow = true;
+                    for(j = i; ++j < source.Length;)
+                    {
+                        c = source[j];
+                        if(c == '\\' && !backslash)
+                        {
+                            backslash = true;
+                            continue;
+                        }
+                        if(c == '\n')
+                        {
+                            lineNo++;
+                            bolIdx = j + 1;
+                        }
+                        else
+                        {
+                            if(!backslash && (c == '\''))
+                                break;
+                            if(backslash && (c == 'n'))
+                                c = '\n';
+                            if(backslash && (c == 't'))
+                                c = '\t';
+                        }
+                        backslash = false;
+                        overflow = !underflow;
+                        underflow = false;
+                        cb = c;
+                    }
+                    if(underflow || overflow)
+                    {
+                        TokenError(i, "character must be exactly one character");
+                    }
+                    else
+                    {
+                        AppendToken(new TokenChar(emsg, filNam, lineNo, i - bolIdx, cb));
+                    }
+                    i = j;
+                    continue;
+                }
+
+                /*
+                 * Check for keywords/names.
+                 */
+                if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c == '$' && options.dollarsigns))
+                {
+                    int j;
+
+                    for(j = i; ++j < source.Length;)
+                    {
+                        c = source[j];
+                        if(c >= 'a' && c <= 'z')
+                            continue;
+                        if(c >= 'A' && c <= 'Z')
+                            continue;
+                        if(c >= '0' && c <= '9')
+                            continue;
+                        if(c == '$' && options.dollarsigns)
+                            continue;
+                        if(c != '_')
+                            break;
+                    }
+                    if(j - i > MAX_NAME_LEN)
+                    {
+                        TokenError(i, "name too long, max " + MAX_NAME_LEN);
+                    }
+                    else
+                    {
+                        string name = source.Substring(i, j - i);
+                        if(name == "quaternion")
+                            name = "rotation";  // see lslangtest1.lsl
+                        if(keywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)keywords[name].Invoke(args));
+                        }
+                        else if(options.arrays && arrayKeywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)arrayKeywords[name].Invoke(args));
+                        }
+                        else if(options.advFlowCtl && advFlowCtlKeywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)advFlowCtlKeywords[name].Invoke(args));
+                        }
+                        else if(options.tryCatch && tryCatchKeywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)tryCatchKeywords[name].Invoke(args));
+                        }
+                        else if(options.objects && objectsKeywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)objectsKeywords[name].Invoke(args));
+                        }
+                        else if(options.chars && charsKeywords.ContainsKey(name))
+                        {
+                            Object[] args = new Object[] { emsg, filNam, lineNo, i - bolIdx };
+                            AppendToken((Token)charsKeywords[name].Invoke(args));
+                        }
+                        else
+                        {
+                            AppendToken(new TokenName(emsg, filNam, lineNo, i - bolIdx, name));
+                        }
+                    }
+                    i = --j;
+                    continue;
+                }
+
+                /*
+                 * Check for option enables.
+                 */
+                if((c == ';') && (lastToken is TokenName) &&
+                        (lastToken.prevToken is TokenName) &&
+                        (strcasecmp(((TokenName)lastToken.prevToken).val, "yoption") == 0))
+                {
+                    string opt = ((TokenName)lastToken).val;
+                    if(strcasecmp(opt, "allowall") == 0)
+                    {
+                        options.arrays = true;
+                        options.advFlowCtl = true;
+                        options.tryCatch = true;
+                        options.objects = true;
+                        options.chars = true;
+                        //                        options.noRightToLeft = true;
+                        options.dollarsigns = true;
+                    }
+                    else if(strcasecmp(opt, "arrays") == 0)
+                        options.arrays = true;
+                    else if(strcasecmp(opt, "advflowctl") == 0)
+                        options.advFlowCtl = true;
+                    else if(strcasecmp(opt, "trycatch") == 0)
+                        options.tryCatch = true;
+                    else if(strcasecmp(opt, "objects") == 0)
+                        options.objects = true;
+                    else if(strcasecmp(opt, "chars") == 0)
+                        options.chars = true;
+                    else if(strcasecmp(opt, "norighttoleft") == 0)
+                        options.noRightToLeft = true;
+                    else if(strcasecmp(opt, "dollarsigns") == 0)
+                        options.dollarsigns = true;
+                    else
+                        lastToken.ErrorMsg("unknown YOption");
+
+                    lastToken = lastToken.prevToken.prevToken;
+                    lastToken.nextToken = null;
+                    continue;
+                }
+
+                /*
+                 * Lastly, check for delimeters.
+                 */
+                {
+                    int j;
+                    int len = 0;
+
+                    for(j = 0; j < delims.Length; j++)
+                    {
+                        len = delims[j].str.Length;
+                        if((i + len <= source.Length) && (source.Substring(i, len).Equals(delims[j].str)))
+                            break;
+                    }
+                    if(j < delims.Length)
+                    {
+                        Object[] args = { emsg, filNam, lineNo, i - bolIdx };
+                        Token kwToken = (Token)delims[j].ctorInfo.Invoke(args);
+                        AppendToken(kwToken);
+                        i += --len;
+                        continue;
+                    }
+                }
+
+                /*
+                 * Don't know what it is!
+                 */
+                TokenError(i, "unknown character '" + c + "'");
+            }
+        }
+
+        private static int strcasecmp(String s, String t)
+        {
+            return String.Compare(s, t, StringComparison.OrdinalIgnoreCase);
+        }
+
+        /**
+         * @brief try to parse a floating-point number from the source
+         * @param i = starting position within this.source of number
+         * @returns 0: not a floating point number, try something else
+         *       else: position in this.source of terminating character, ie, past number
+         *             TokenFloat appended to token list
+         *             or error message has been output
+         */
+        private int TryParseFloat(int i)
+        {
+            bool decimals, error, negexp, nulexp;
+            char c;
+            double f, f10;
+            int exponent, j, x, y;
+            ulong m, mantissa;
+
+            decimals = false;
+            error = false;
+            exponent = 0;
+            mantissa = 0;
+            for(j = i; j < source.Length; j++)
+            {
+                c = source[j];
+                if((c >= '0') && (c <= '9'))
+                {
+                    m = mantissa * 10 + (ulong)(c - '0');
+                    if(m / 10 != mantissa)
+                    {
+                        if(!decimals)
+                            exponent++;
+                    }
+                    else
+                    {
+                        mantissa = m;
+                        if(decimals)
+                            exponent--;
+                    }
+                    continue;
+                }
+                if(c == '.')
+                {
+                    if(decimals)
+                    {
+                        TokenError(i, "more than one decimal point");
+                        return j;
+                    }
+                    decimals = true;
+                    continue;
+                }
+                if((c == 'E') || (c == 'e'))
+                {
+                    if(++j >= source.Length)
+                    {
+                        TokenError(i, "floating exponent off end of source");
+                        return j;
+                    }
+                    c = source[j];
+                    negexp = (c == '-');
+                    if(negexp || (c == '+'))
+                        j++;
+                    y = 0;
+                    nulexp = true;
+                    for(; j < source.Length; j++)
+                    {
+                        c = source[j];
+                        if((c < '0') || (c > '9'))
+                            break;
+                        x = y * 10 + (c - '0');
+                        if(x / 10 != y)
+                        {
+                            if(!error)
+                                TokenError(i, "floating exponent overflow");
+                            error = true;
+                        }
+                        y = x;
+                        nulexp = false;
+                    }
+                    if(nulexp)
+                    {
+                        TokenError(i, "bad or missing floating exponent");
+                        return j;
+                    }
+                    if(negexp)
+                    {
+                        x = exponent - y;
+                        if(x > exponent)
+                        {
+                            if(!error)
+                                TokenError(i, "floating exponent overflow");
+                            error = true;
+                        }
+                    }
+                    else
+                    {
+                        x = exponent + y;
+                        if(x < exponent)
+                        {
+                            if(!error)
+                                TokenError(i, "floating exponent overflow");
+                            error = true;
+                        }
+                    }
+                    exponent = x;
+                }
+                break;
+            }
+            if(!decimals)
+            {
+                return 0;
+            }
+
+            f = mantissa;
+            if((exponent != 0) && (mantissa != 0) && !error)
+            {
+                f10 = 10.0;
+                if(exponent < 0)
+                {
+                    exponent = -exponent;
+                    while(exponent > 0)
+                    {
+                        if((exponent & 1) != 0)
+                        {
+                            f /= f10;
+                        }
+                        exponent /= 2;
+                        f10 *= f10;
+                    }
+                }
+                else
+                {
+                    while(exponent > 0)
+                    {
+                        if((exponent & 1) != 0)
+                        {
+                            f *= f10;
+                        }
+                        exponent /= 2;
+                        f10 *= f10;
+                    }
+                }
+            }
+            if(!error)
+            {
+                AppendToken(new TokenFloat(emsg, filNam, lineNo, i - bolIdx, f));
+            }
+            return j;
+        }
+
+        /**
+         * @brief try to parse an integer number from the source
+         * @param i = starting position within this.source of number
+         * @returns 0: not an integer number, try something else
+         *       else: position in this.source of terminating character, ie, past number
+         *             TokenInt appended to token list
+         *             or error message has been output
+         */
+        private int TryParseInt(int i)
+        {
+            bool error;
+            char c;
+            int j;
+            uint basse, m, mantissa;
+
+            basse = 10;
+            error = false;
+            mantissa = 0;
+            for(j = i; j < source.Length; j++)
+            {
+                c = source[j];
+                if((c >= '0') && (c <= '9'))
+                {
+                    m = mantissa * basse + (uint)(c - '0');
+                    if(m / basse != mantissa)
+                    {
+                        if(!error)
+                            TokenError(i, "integer overflow");
+                        error = true;
+                    }
+                    mantissa = m;
+                    continue;
+                }
+                if((basse == 16) && ((c >= 'A') && (c <= 'F')))
+                {
+                    m = mantissa * basse + (uint)(c - 'A') + 10U;
+                    if(m / basse != mantissa)
+                    {
+                        if(!error)
+                            TokenError(i, "integer overflow");
+                        error = true;
+                    }
+                    mantissa = m;
+                    continue;
+                }
+                if((basse == 16) && ((c >= 'a') && (c <= 'f')))
+                {
+                    m = mantissa * basse + (uint)(c - 'a') + 10U;
+                    if(m / basse != mantissa)
+                    {
+                        if(!error)
+                            TokenError(i, "integer overflow");
+                        error = true;
+                    }
+                    mantissa = m;
+                    continue;
+                }
+                if(((c == 'x') || (c == 'X')) && (mantissa == 0) && (basse == 10))
+                {
+                    basse = 16;
+                    continue;
+                }
+                break;
+            }
+            if(!error)
+            {
+                AppendToken(new TokenInt(emsg, filNam, lineNo, i - bolIdx, (int)mantissa));
+            }
+            return j;
+        }
+
+        /**
+         * @brief append token on to end of list
+         * @param newToken = token to append
+         * @returns with token appended onto this.lastToken
+         */
+        private void AppendToken(Token newToken)
+        {
+            newToken.nextToken = null;
+            newToken.prevToken = lastToken;
+            newToken.nr2l = this.options.noRightToLeft;
+            lastToken.nextToken = newToken;
+            lastToken = newToken;
+        }
+
+        /**
+         * @brief print tokenizing error message
+         *        and remember that we've an error
+         * @param i = position within source file of the error
+         * @param message = error message text
+         * @returns with this.youveAnError set
+         */
+        private void TokenError(int i, string message)
+        {
+            Token temp = new Token(this.emsg, this.filNam, this.lineNo, i - this.bolIdx);
+            temp.ErrorMsg(message);
+            youveAnError = true;
+        }
+
+        /**
+         * @brief get a token's constructor
+         * @param tokenType = token's type
+         * @returns token's constructor
+         */
+        private static Type[] constrTypes = new Type[] {
+            typeof (TokenErrorMessage), typeof (string), typeof (int), typeof (int)
+        };
+
+        private static System.Reflection.ConstructorInfo GetTokenCtor(Type tokenType)
+        {
+            return tokenType.GetConstructor(constrTypes);
+        }
+
+        /**
+         * @brief delimeter table
+         */
+        private class Delim
+        {
+            public string str;
+            public System.Reflection.ConstructorInfo ctorInfo;
+            public Delim(string str, Type type)
+            {
+                this.str = str;
+                ctorInfo = GetTokenCtor(type);
+            }
+        }
+
+        private static Delim[] delims = new Delim[] {
+            new Delim ("...", typeof (TokenKwDotDotDot)),
+            new Delim ("&&&", typeof (TokenKwAndAndAnd)),
+            new Delim ("|||", typeof (TokenKwOrOrOr)),
+            new Delim ("<<=", typeof (TokenKwAsnLSh)),
+            new Delim (">>=", typeof (TokenKwAsnRSh)),
+            new Delim ("<=",  typeof (TokenKwCmpLE)),
+            new Delim (">=",  typeof (TokenKwCmpGE)),
+            new Delim ("==",  typeof (TokenKwCmpEQ)),
+            new Delim ("!=",  typeof (TokenKwCmpNE)),
+            new Delim ("++",  typeof (TokenKwIncr)),
+            new Delim ("--",  typeof (TokenKwDecr)),
+            new Delim ("&&",  typeof (TokenKwAndAnd)),
+            new Delim ("||",  typeof (TokenKwOrOr)),
+            new Delim ("+=",  typeof (TokenKwAsnAdd)),
+            new Delim ("&=",  typeof (TokenKwAsnAnd)),
+            new Delim ("-=",  typeof (TokenKwAsnSub)),
+            new Delim ("*=",  typeof (TokenKwAsnMul)),
+            new Delim ("/=",  typeof (TokenKwAsnDiv)),
+            new Delim ("%=",  typeof (TokenKwAsnMod)),
+            new Delim ("|=",  typeof (TokenKwAsnOr)),
+            new Delim ("^=",  typeof (TokenKwAsnXor)),
+            new Delim ("<<",  typeof (TokenKwLSh)),
+            new Delim (">>",  typeof (TokenKwRSh)),
+            new Delim ("~",   typeof (TokenKwTilde)),
+            new Delim ("!",   typeof (TokenKwExclam)),
+            new Delim ("@",   typeof (TokenKwAt)),
+            new Delim ("%",   typeof (TokenKwMod)),
+            new Delim ("^",   typeof (TokenKwXor)),
+            new Delim ("&",   typeof (TokenKwAnd)),
+            new Delim ("*",   typeof (TokenKwMul)),
+            new Delim ("(",   typeof (TokenKwParOpen)),
+            new Delim (")",   typeof (TokenKwParClose)),
+            new Delim ("-",   typeof (TokenKwSub)),
+            new Delim ("+",   typeof (TokenKwAdd)),
+            new Delim ("=",   typeof (TokenKwAssign)),
+            new Delim ("{",   typeof (TokenKwBrcOpen)),
+            new Delim ("}",   typeof (TokenKwBrcClose)),
+            new Delim ("[",   typeof (TokenKwBrkOpen)),
+            new Delim ("]",   typeof (TokenKwBrkClose)),
+            new Delim (";",   typeof (TokenKwSemi)),
+            new Delim (":",   typeof (TokenKwColon)),
+            new Delim ("<",   typeof (TokenKwCmpLT)),
+            new Delim (">",   typeof (TokenKwCmpGT)),
+            new Delim (",",   typeof (TokenKwComma)),
+            new Delim (".",   typeof (TokenKwDot)),
+            new Delim ("?",   typeof (TokenKwQMark)),
+            new Delim ("/",   typeof (TokenKwDiv)),
+            new Delim ("|",   typeof (TokenKwOr)),
+            new Delim ("#",   typeof (TokenKwHash))
+        };
+
+        /**
+         * @brief keyword tables
+         *        The keyword tables translate a keyword string
+         *        to the corresponding token constructor.
+         */
+        private static Dictionary<string, System.Reflection.ConstructorInfo> keywords = BuildKeywords();
+        private static Dictionary<string, System.Reflection.ConstructorInfo> arrayKeywords = BuildArrayKeywords();
+        private static Dictionary<string, System.Reflection.ConstructorInfo> advFlowCtlKeywords = BuildAdvFlowCtlKeywords();
+        private static Dictionary<string, System.Reflection.ConstructorInfo> tryCatchKeywords = BuildTryCatchKeywords();
+        private static Dictionary<string, System.Reflection.ConstructorInfo> objectsKeywords = BuildObjectsKeywords();
+        private static Dictionary<string, System.Reflection.ConstructorInfo> charsKeywords = BuildCharsKeywords();
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("default", GetTokenCtor(typeof(TokenKwDefault)));
+            kws.Add("do", GetTokenCtor(typeof(TokenKwDo)));
+            kws.Add("else", GetTokenCtor(typeof(TokenKwElse)));
+            kws.Add("float", GetTokenCtor(typeof(TokenTypeFloat)));
+            kws.Add("for", GetTokenCtor(typeof(TokenKwFor)));
+            kws.Add("if", GetTokenCtor(typeof(TokenKwIf)));
+            kws.Add("integer", GetTokenCtor(typeof(TokenTypeInt)));
+            kws.Add("list", GetTokenCtor(typeof(TokenTypeList)));
+            kws.Add("jump", GetTokenCtor(typeof(TokenKwJump)));
+            kws.Add("key", GetTokenCtor(typeof(TokenTypeKey)));
+            kws.Add("return", GetTokenCtor(typeof(TokenKwRet)));
+            kws.Add("rotation", GetTokenCtor(typeof(TokenTypeRot)));
+            kws.Add("state", GetTokenCtor(typeof(TokenKwState)));
+            kws.Add("string", GetTokenCtor(typeof(TokenTypeStr)));
+            kws.Add("vector", GetTokenCtor(typeof(TokenTypeVec)));
+            kws.Add("while", GetTokenCtor(typeof(TokenKwWhile)));
+
+            return kws;
+        }
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildArrayKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("array", GetTokenCtor(typeof(TokenTypeArray)));
+            kws.Add("foreach", GetTokenCtor(typeof(TokenKwForEach)));
+            kws.Add("in", GetTokenCtor(typeof(TokenKwIn)));
+            kws.Add("is", GetTokenCtor(typeof(TokenKwIs)));
+            kws.Add("object", GetTokenCtor(typeof(TokenTypeObject)));
+            kws.Add("undef", GetTokenCtor(typeof(TokenKwUndef)));
+
+            return kws;
+        }
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildAdvFlowCtlKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("break", GetTokenCtor(typeof(TokenKwBreak)));
+            kws.Add("case", GetTokenCtor(typeof(TokenKwCase)));
+            kws.Add("constant", GetTokenCtor(typeof(TokenKwConst)));
+            kws.Add("continue", GetTokenCtor(typeof(TokenKwCont)));
+            kws.Add("switch", GetTokenCtor(typeof(TokenKwSwitch)));
+
+            return kws;
+        }
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildTryCatchKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("catch", GetTokenCtor(typeof(TokenKwCatch)));
+            kws.Add("exception", GetTokenCtor(typeof(TokenTypeExc)));
+            kws.Add("finally", GetTokenCtor(typeof(TokenKwFinally)));
+            kws.Add("throw", GetTokenCtor(typeof(TokenKwThrow)));
+            kws.Add("try", GetTokenCtor(typeof(TokenKwTry)));
+
+            return kws;
+        }
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildObjectsKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("abstract", GetTokenCtor(typeof(TokenKwAbstract)));
+            kws.Add("base", GetTokenCtor(typeof(TokenKwBase)));
+            kws.Add("class", GetTokenCtor(typeof(TokenKwClass)));
+            kws.Add("constructor", GetTokenCtor(typeof(TokenKwConstructor)));
+            kws.Add("delegate", GetTokenCtor(typeof(TokenKwDelegate)));
+            kws.Add("destructor", GetTokenCtor(typeof(TokenKwDestructor)));
+            kws.Add("final", GetTokenCtor(typeof(TokenKwFinal)));
+            kws.Add("get", GetTokenCtor(typeof(TokenKwGet)));
+            kws.Add("interface", GetTokenCtor(typeof(TokenKwInterface)));
+            kws.Add("new", GetTokenCtor(typeof(TokenKwNew)));
+            kws.Add("override", GetTokenCtor(typeof(TokenKwOverride)));
+            kws.Add("partial", GetTokenCtor(typeof(TokenKwPartial)));
+            kws.Add("private", GetTokenCtor(typeof(TokenKwPrivate)));
+            kws.Add("protected", GetTokenCtor(typeof(TokenKwProtected)));
+            kws.Add("public", GetTokenCtor(typeof(TokenKwPublic)));
+            kws.Add("set", GetTokenCtor(typeof(TokenKwSet)));
+            kws.Add("static", GetTokenCtor(typeof(TokenKwStatic)));
+            kws.Add("this", GetTokenCtor(typeof(TokenKwThis)));
+            kws.Add("typedef", GetTokenCtor(typeof(TokenKwTypedef)));
+            kws.Add("virtual", GetTokenCtor(typeof(TokenKwVirtual)));
+
+            return kws;
+        }
+
+        private static Dictionary<string, System.Reflection.ConstructorInfo> BuildCharsKeywords()
+        {
+            Dictionary<string, System.Reflection.ConstructorInfo> kws = new Dictionary<string, System.Reflection.ConstructorInfo>();
+
+            kws.Add("char", GetTokenCtor(typeof(TokenTypeChar)));
+
+            return kws;
+        }
+    }
+
+    /**
+     * @brief All output token types in addition to TokenBegin.
+     *        They are all sub-types of Token.
+     */
+
+    public class TokenChar: Token
+    {
+        public char val;
+        public TokenChar(TokenErrorMessage emsg, string file, int line, int posn, char val) : base(emsg, file, line, posn)
+        {
+            this.val = val;
+        }
+        public TokenChar(Token original, char val) : base(original)
+        {
+            this.val = val;
+        }
+        public override string ToString()
+        {
+            switch(val)
+            {
+                case '\'':
+                    return "'\\''";
+                case '\\':
+                    return "'\\\\'";
+                case '\n':
+                    return "'\\n'";
+                case '\t':
+                    return "'\\t'";
+                default:
+                    return "'" + val + "'";
+            }
+        }
+    }
+
+    public class TokenFloat: Token
+    {
+        public double val;
+        public TokenFloat(TokenErrorMessage emsg, string file, int line, int posn, double val) : base(emsg, file, line, posn)
+        {
+            this.val = val;
+        }
+        public override string ToString()
+        {
+            return val.ToString();
+        }
+    }
+
+    public class TokenInt: Token
+    {
+        public int val;
+        public TokenInt(TokenErrorMessage emsg, string file, int line, int posn, int val) : base(emsg, file, line, posn)
+        {
+            this.val = val;
+        }
+        public TokenInt(Token original, int val) : base(original)
+        {
+            this.val = val;
+        }
+        public override string ToString()
+        {
+            return val.ToString();
+        }
+    }
+
+    public class TokenName: Token
+    {
+        public string val;
+        public TokenName(TokenErrorMessage emsg, string file, int line, int posn, string val) : base(emsg, file, line, posn)
+        {
+            this.val = val;
+        }
+        public TokenName(Token original, string val) : base(original)
+        {
+            this.val = val;
+        }
+        public override string ToString()
+        {
+            return this.val;
+        }
+    }
+
+    public class TokenStr: Token
+    {
+        public string val;
+        public TokenStr(TokenErrorMessage emsg, string file, int line, int posn, string val) : base(emsg, file, line, posn)
+        {
+            this.val = val;
+        }
+        public override string ToString()
+        {
+            if((val.IndexOf('"') < 0) &&
+                (val.IndexOf('\\') < 0) &&
+                (val.IndexOf('\n') < 0) &&
+                (val.IndexOf('\t') < 0))
+                return "\"" + val + "\"";
+
+            int len = val.Length;
+            StringBuilder sb = new StringBuilder(len * 2 + 2);
+            sb.Append('"');
+            for(int i = 0; i < len; i++)
+            {
+                char c = val[i];
+                switch(c)
+                {
+                    case '"':
+                        {
+                            sb.Append('\\');
+                            sb.Append('"');
+                            break;
+                        }
+                    case '\\':
+                        {
+                            sb.Append('\\');
+                            sb.Append('\\');
+                            break;
+                        }
+                    case '\n':
+                        {
+                            sb.Append('\\');
+                            sb.Append('n');
+                            break;
+                        }
+                    case '\t':
+                        {
+                            sb.Append('\\');
+                            sb.Append('t');
+                            break;
+                        }
+                    default:
+                        {
+                            sb.Append(c);
+                            break;
+                        }
+                }
+            }
+            return sb.ToString();
+        }
+    }
+
+    /*
+     * This one marks the end-of-file.
+     */
+    public class TokenEnd: Token
+    {
+        public TokenEnd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+    }
+
+    /*
+     * Various keywords and delimeters.
+     */
+    public delegate object TokenRValConstBinOpDelegate(object left, object right);
+    public delegate object TokenRValConstUnOpDelegate(object right);
+
+    public class TokenKw: Token
+    {
+        public TokenRValConstBinOpDelegate binOpConst;
+        public TokenRValConstUnOpDelegate unOpConst;
+        public bool sdtClassOp;
+        public TokenKw(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn)
+        {
+        }
+        public TokenKw(Token original) : base(original)
+        {
+        }
+    }
+
+    public class TokenKwDotDotDot: TokenKw
+    {
+        public TokenKwDotDotDot(TokenErrorMessage emsg, string file,
+                                int line, int posn) : base(emsg, file, line, posn)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public TokenKwDotDotDot(Token original) : base(original)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public override string ToString()
+        {
+            return "...";
+        }
+    }
+    public class TokenKwAndAndAnd: TokenKw
+    {
+        public TokenKwAndAndAnd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public TokenKwAndAndAnd(Token original) : base(original)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public override string ToString()
+        {
+            return "&&&";
+        }
+    }
+    public class TokenKwOrOrOr: TokenKw
+    {
+        public TokenKwOrOrOr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public TokenKwOrOrOr(Token original) : base(original)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = false;
+        }
+        public override string ToString()
+        {
+            return "|||";
+        }
+    }
+    public class TokenKwAsnLSh: TokenKw
+    {
+        public TokenKwAsnLSh(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = true;
+        }
+        public TokenKwAsnLSh(Token original) : base(original)
+        {
+            binOpConst = TokenRValConstOps.Null;
+            unOpConst = TokenRValConstOps.Null;
+            sdtClassOp = true;
+        }
+        public override string ToString()
+        {
+            return "<<=";
+        }
+    }
+    public class TokenKwAsnRSh: TokenKw
+    {
+        public TokenKwAsnRSh(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnRSh(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return ">>=";
+        }
+    }
+    public class TokenKwCmpLE: TokenKw
+    {
+        public TokenKwCmpLE(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpLE(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "<=";
+        }
+    }
+    public class TokenKwCmpGE: TokenKw
+    {
+        public TokenKwCmpGE(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpGE(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return ">=";
+        }
+    }
+    public class TokenKwCmpEQ: TokenKw
+    {
+        public TokenKwCmpEQ(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpEQ(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "==";
+        }
+    }
+    public class TokenKwCmpNE: TokenKw
+    {
+        public TokenKwCmpNE(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpNE(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "!=";
+        }
+    }
+    public class TokenKwIncr: TokenKw
+    {
+        public TokenKwIncr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwIncr(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "++";
+        }
+    }
+    public class TokenKwDecr: TokenKw
+    {
+        public TokenKwDecr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDecr(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "--";
+        }
+    }
+    public class TokenKwAndAnd: TokenKw
+    {
+        public TokenKwAndAnd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAndAnd(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "&&";
+        }
+    }
+    public class TokenKwOrOr: TokenKw
+    {
+        public TokenKwOrOr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwOrOr(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "||";
+        }
+    }
+    public class TokenKwAsnAdd: TokenKw
+    {
+        public TokenKwAsnAdd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnAdd(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "+=";
+        }
+    }
+    public class TokenKwAsnAnd: TokenKw
+    {
+        public TokenKwAsnAnd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnAnd(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "&=";
+        }
+    }
+    public class TokenKwAsnSub: TokenKw
+    {
+        public TokenKwAsnSub(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnSub(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "-=";
+        }
+    }
+    public class TokenKwAsnMul: TokenKw
+    {
+        public TokenKwAsnMul(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnMul(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "*=";
+        }
+    }
+    public class TokenKwAsnDiv: TokenKw
+    {
+        public TokenKwAsnDiv(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnDiv(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "/=";
+        }
+    }
+    public class TokenKwAsnMod: TokenKw
+    {
+        public TokenKwAsnMod(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnMod(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "%=";
+        }
+    }
+    public class TokenKwAsnOr: TokenKw
+    {
+        public TokenKwAsnOr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnOr(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "|=";
+        }
+    }
+    public class TokenKwAsnXor: TokenKw
+    {
+        public TokenKwAsnXor(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAsnXor(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "^=";
+        }
+    }
+    public class TokenKwLSh: TokenKw
+    {
+        public TokenKwLSh(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.LSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwLSh(Token original) : base(original) { binOpConst = TokenRValConstOps.LSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "<<";
+        }
+    }
+    public class TokenKwRSh: TokenKw
+    {
+        public TokenKwRSh(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.RSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwRSh(Token original) : base(original) { binOpConst = TokenRValConstOps.RSh; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return ">>";
+        }
+    }
+    public class TokenKwTilde: TokenKw
+    {
+        public TokenKwTilde(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Not; sdtClassOp = true; }
+        public TokenKwTilde(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Not; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "~";
+        }
+    }
+    public class TokenKwExclam: TokenKw
+    {
+        public TokenKwExclam(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwExclam(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "!";
+        }
+    }
+    public class TokenKwAt: TokenKw
+    {
+        public TokenKwAt(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwAt(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "@";
+        }
+    }
+    public class TokenKwMod: TokenKw
+    {
+        public TokenKwMod(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Mod; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwMod(Token original) : base(original) { binOpConst = TokenRValConstOps.Mod; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "%";
+        }
+    }
+    public class TokenKwXor: TokenKw
+    {
+        public TokenKwXor(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Xor; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwXor(Token original) : base(original) { binOpConst = TokenRValConstOps.Xor; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "^";
+        }
+    }
+    public class TokenKwAnd: TokenKw
+    {
+        public TokenKwAnd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.And; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAnd(Token original) : base(original) { binOpConst = TokenRValConstOps.And; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "&";
+        }
+    }
+    public class TokenKwMul: TokenKw
+    {
+        public TokenKwMul(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Mul; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwMul(Token original) : base(original) { binOpConst = TokenRValConstOps.Mul; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "*";
+        }
+    }
+    public class TokenKwParOpen: TokenKw
+    {
+        public TokenKwParOpen(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwParOpen(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "(";
+        }
+    }
+    public class TokenKwParClose: TokenKw
+    {
+        public TokenKwParClose(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwParClose(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return ")";
+        }
+    }
+    public class TokenKwSub: TokenKw
+    {
+        public TokenKwSub(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Sub; unOpConst = TokenRValConstOps.Neg; sdtClassOp = true; }
+        public TokenKwSub(Token original) : base(original) { binOpConst = TokenRValConstOps.Sub; unOpConst = TokenRValConstOps.Neg; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "-";
+        }
+    }
+    public class TokenKwAdd: TokenKw
+    {
+        public TokenKwAdd(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Add; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwAdd(Token original) : base(original) { binOpConst = TokenRValConstOps.Add; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "+";
+        }
+    }
+    public class TokenKwAssign: TokenKw
+    {
+        public TokenKwAssign(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwAssign(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "=";
+        }
+    }
+    public class TokenKwBrcOpen: TokenKw
+    {
+        public TokenKwBrcOpen(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBrcOpen(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "{";
+        }
+    }
+    public class TokenKwBrcClose: TokenKw
+    {
+        public TokenKwBrcClose(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBrcClose(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "}";
+        }
+    }
+    public class TokenKwBrkOpen: TokenKw
+    {
+        public TokenKwBrkOpen(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBrkOpen(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "[";
+        }
+    }
+    public class TokenKwBrkClose: TokenKw
+    {
+        public TokenKwBrkClose(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBrkClose(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "]";
+        }
+    }
+    public class TokenKwSemi: TokenKw
+    {
+        public TokenKwSemi(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwSemi(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return ";";
+        }
+    }
+    public class TokenKwColon: TokenKw
+    {
+        public TokenKwColon(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwColon(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return ":";
+        }
+    }
+    public class TokenKwCmpLT: TokenKw
+    {
+        public TokenKwCmpLT(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpLT(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "<";
+        }
+    }
+    public class TokenKwCmpGT: TokenKw
+    {
+        public TokenKwCmpGT(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwCmpGT(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return ">";
+        }
+    }
+    public class TokenKwComma: TokenKw
+    {
+        public TokenKwComma(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwComma(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return ",";
+        }
+    }
+    public class TokenKwDot: TokenKw
+    {
+        public TokenKwDot(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDot(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return ".";
+        }
+    }
+    public class TokenKwQMark: TokenKw
+    {
+        public TokenKwQMark(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwQMark(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "?";
+        }
+    }
+    public class TokenKwDiv: TokenKw
+    {
+        public TokenKwDiv(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Div; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwDiv(Token original) : base(original) { binOpConst = TokenRValConstOps.Div; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "/";
+        }
+    }
+    public class TokenKwOr: TokenKw
+    {
+        public TokenKwOr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Or; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public TokenKwOr(Token original) : base(original) { binOpConst = TokenRValConstOps.Or; unOpConst = TokenRValConstOps.Null; sdtClassOp = true; }
+        public override string ToString()
+        {
+            return "|";
+        }
+    }
+    public class TokenKwHash: TokenKw
+    {
+        public TokenKwHash(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwHash(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "#";
+        }
+    }
+
+    public class TokenKwAbstract: TokenKw
+    {
+        public TokenKwAbstract(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwAbstract(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "abstract";
+        }
+    }
+    public class TokenKwBase: TokenKw
+    {
+        public TokenKwBase(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBase(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "base";
+        }
+    }
+    public class TokenKwBreak: TokenKw
+    {
+        public TokenKwBreak(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwBreak(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "break";
+        }
+    }
+    public class TokenKwCase: TokenKw
+    {
+        public TokenKwCase(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwCase(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "case";
+        }
+    }
+    public class TokenKwCatch: TokenKw
+    {
+        public TokenKwCatch(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwCatch(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "catch";
+        }
+    }
+    public class TokenKwClass: TokenKw
+    {
+        public TokenKwClass(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwClass(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "class";
+        }
+    }
+    public class TokenKwConst: TokenKw
+    {
+        public TokenKwConst(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwConst(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "constant";
+        }
+    }
+    public class TokenKwConstructor: TokenKw
+    {
+        public TokenKwConstructor(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwConstructor(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "constructor";
+        }
+    }
+    public class TokenKwCont: TokenKw
+    {
+        public TokenKwCont(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwCont(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "continue";
+        }
+    }
+    public class TokenKwDelegate: TokenKw
+    {
+        public TokenKwDelegate(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDelegate(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "delegate";
+        }
+    }
+    public class TokenKwDefault: TokenKw
+    {
+        public TokenKwDefault(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDefault(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "default";
+        }
+    }
+    public class TokenKwDestructor: TokenKw
+    {
+        public TokenKwDestructor(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDestructor(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "destructor";
+        }
+    }
+    public class TokenKwDo: TokenKw
+    {
+        public TokenKwDo(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwDo(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "do";
+        }
+    }
+    public class TokenKwElse: TokenKw
+    {
+        public TokenKwElse(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwElse(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "else";
+        }
+    }
+    public class TokenKwFinal: TokenKw
+    {
+        public TokenKwFinal(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwFinal(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "final";
+        }
+    }
+    public class TokenKwFinally: TokenKw
+    {
+        public TokenKwFinally(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwFinally(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "finally";
+        }
+    }
+    public class TokenKwFor: TokenKw
+    {
+        public TokenKwFor(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwFor(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "for";
+        }
+    }
+    public class TokenKwForEach: TokenKw
+    {
+        public TokenKwForEach(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwForEach(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "foreach";
+        }
+    }
+    public class TokenKwGet: TokenKw
+    {
+        public TokenKwGet(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwGet(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "get";
+        }
+    }
+    public class TokenKwIf: TokenKw
+    {
+        public TokenKwIf(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwIf(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "if";
+        }
+    }
+    public class TokenKwIn: TokenKw
+    {
+        public TokenKwIn(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwIn(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "in";
+        }
+    }
+    public class TokenKwInterface: TokenKw
+    {
+        public TokenKwInterface(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwInterface(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "interface";
+        }
+    }
+    public class TokenKwIs: TokenKw
+    {
+        public TokenKwIs(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwIs(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "is";
+        }
+    }
+    public class TokenKwJump: TokenKw
+    {
+        public TokenKwJump(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwJump(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "jump";
+        }
+    }
+    public class TokenKwNew: TokenKw
+    {
+        public TokenKwNew(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwNew(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "new";
+        }
+    }
+    public class TokenKwOverride: TokenKw
+    {
+        public TokenKwOverride(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwOverride(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "override";
+        }
+    }
+    public class TokenKwPartial: TokenKw
+    {
+        public TokenKwPartial(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwPartial(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "partial";
+        }
+    }
+    public class TokenKwPrivate: TokenKw
+    {
+        public TokenKwPrivate(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwPrivate(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "private";
+        }
+    }
+    public class TokenKwProtected: TokenKw
+    {
+        public TokenKwProtected(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwProtected(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "protected";
+        }
+    }
+    public class TokenKwPublic: TokenKw
+    {
+        public TokenKwPublic(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwPublic(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "public";
+        }
+    }
+    public class TokenKwRet: TokenKw
+    {
+        public TokenKwRet(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwRet(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "return";
+        }
+    }
+    public class TokenKwSet: TokenKw
+    {
+        public TokenKwSet(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwSet(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "set";
+        }
+    }
+    public class TokenKwState: TokenKw
+    {
+        public TokenKwState(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwState(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "state";
+        }
+    }
+    public class TokenKwStatic: TokenKw
+    {
+        public TokenKwStatic(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwStatic(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "static";
+        }
+    }
+    public class TokenKwSwitch: TokenKw
+    {
+        public TokenKwSwitch(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwSwitch(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "switch";
+        }
+    }
+    public class TokenKwThis: TokenKw
+    {
+        public TokenKwThis(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwThis(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "this";
+        }
+    }
+    public class TokenKwThrow: TokenKw
+    {
+        public TokenKwThrow(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwThrow(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "throw";
+        }
+    }
+    public class TokenKwTry: TokenKw
+    {
+        public TokenKwTry(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwTry(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "try";
+        }
+    }
+    public class TokenKwTypedef: TokenKw
+    {
+        public TokenKwTypedef(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwTypedef(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "typedef";
+        }
+    }
+    public class TokenKwUndef: TokenKw
+    {
+        public TokenKwUndef(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwUndef(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "undef";
+        }
+    }
+    public class TokenKwVirtual: TokenKw
+    {
+        public TokenKwVirtual(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwVirtual(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "virtual";
+        }
+    }
+    public class TokenKwWhile: TokenKw
+    {
+        public TokenKwWhile(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public TokenKwWhile(Token original) : base(original) { binOpConst = TokenRValConstOps.Null; unOpConst = TokenRValConstOps.Null; sdtClassOp = false; }
+        public override string ToString()
+        {
+            return "while";
+        }
+    }
+
+    /**
+     * @brief These static functions attempt to perform arithmetic on two constant
+     *        operands to generate the resultant constant.
+     *        Likewise for unary operators.
+     *
+     * @param left  = left-hand value
+     * @param right = right-hand value
+     * @returns null: not able to perform computation
+     *          else: resultant value object
+     *
+     * Note: it is ok for these to throw any exception (such as overflow or div-by-zero), 
+     *       and it will be treated as the 'not able to perform computation' case.
+     */
+    public class TokenRValConstOps
+    {
+        public static object Null(object left, object right)
+        {
+            return null;
+        }
+        public static object Div(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left / (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left / (double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (double)left / (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (double)left / (double)right;
+            }
+            return null;
+        }
+        public static object Mod(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left % (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left % (double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (double)left % (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (double)left % (double)right;
+            }
+            return null;
+        }
+        public static object Mul(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left * (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left * (double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (double)left * (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (double)left * (double)right;
+            }
+            return null;
+        }
+        public static object And(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left & (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left & (int)(double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (int)(double)left & (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (int)(double)left & (int)(double)right;
+            }
+            return null;
+        }
+        public static object LSh(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left << (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left << (int)(double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (int)(double)left << (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (int)(double)left << (int)(double)right;
+            }
+            return null;
+        }
+        public static object Or(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left | (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left | (int)(double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (int)(double)left | (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (int)(double)left | (int)(double)right;
+            }
+            return null;
+        }
+        public static object RSh(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left >> (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left >> (int)(double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (int)(double)left >> (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (int)(double)left >> (int)(double)right;
+            }
+            return null;
+        }
+        public static object Xor(object left, object right)
+        {
+            if((left is int) && (right is int))
+            {
+                return (int)left ^ (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left ^ (int)(double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (int)(double)left ^ (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (int)(double)left ^ (int)(double)right;
+            }
+            return null;
+        }
+        public static object Add(object left, object right)
+        {
+            if((left is char) && (right is int))
+            {
+                return (char)((char)left + (int)right);
+            }
+            if((left is double) && (right is double))
+            {
+                return (double)left + (double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (double)left + (int)right;
+            }
+            if((left is double) && (right is string))
+            {
+                return TypeCast.FloatToString((double)left) + (string)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left + (double)right;
+            }
+            if((left is int) && (right is int))
+            {
+                return (int)left + (int)right;
+            }
+            if((left is int) && (right is string))
+            {
+                return TypeCast.IntegerToString((int)left) + (string)right;
+            }
+            if((left is string) && (right is char))
+            {
+                return (string)left + (char)right;
+            }
+            if((left is string) && (right is double))
+            {
+                return (string)left + TypeCast.FloatToString((double)right);
+            }
+            if((left is string) && (right is int))
+            {
+                return (string)left + TypeCast.IntegerToString((int)right);
+            }
+            if((left is string) && (right is string))
+            {
+                return (string)left + (string)right;
+            }
+            return null;
+        }
+        public static object Sub(object left, object right)
+        {
+            if((left is char) && (right is int))
+            {
+                return (char)((char)left - (int)right);
+            }
+            if((left is int) && (right is int))
+            {
+                return (int)left - (int)right;
+            }
+            if((left is int) && (right is double))
+            {
+                return (int)left - (double)right;
+            }
+            if((left is double) && (right is int))
+            {
+                return (double)left - (int)right;
+            }
+            if((left is double) && (right is double))
+            {
+                return (double)left - (double)right;
+            }
+            return null;
+        }
+        public static object Null(object right)
+        {
+            return null;
+        }
+        public static object Neg(object right)
+        {
+            if(right is int)
+            {
+                return -(int)right;
+            }
+            if(right is double)
+            {
+                return -(double)right;
+            }
+            return null;
+        }
+        public static object Not(object right)
+        {
+            if(right is int)
+            {
+                return ~(int)right;
+            }
+            return null;
+        }
+    }
+
+    /*
+     * Various datatypes.
+     */
+    public abstract class TokenType: Token
+    {
+
+        public TokenType(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenType(Token original) : base(original) { }
+
+        public static TokenType FromSysType(Token original, System.Type typ)
+        {
+            if(typ == typeof(LSL_List))
+                return new TokenTypeList(original);
+            if(typ == typeof(LSL_Rotation))
+                return new TokenTypeRot(original);
+            if(typ == typeof(void))
+                return new TokenTypeVoid(original);
+            if(typ == typeof(LSL_Vector))
+                return new TokenTypeVec(original);
+            if(typ == typeof(float))
+                return new TokenTypeFloat(original);
+            if(typ == typeof(int))
+                return new TokenTypeInt(original);
+            if(typ == typeof(string))
+                return new TokenTypeStr(original);
+            if(typ == typeof(double))
+                return new TokenTypeFloat(original);
+            if(typ == typeof(bool))
+                return new TokenTypeBool(original);
+            if(typ == typeof(object))
+                return new TokenTypeObject(original);
+            if(typ == typeof(XMR_Array))
+                return new TokenTypeArray(original);
+            if(typ == typeof(LSL_Integer))
+                return new TokenTypeLSLInt(original);
+            if(typ == typeof(LSL_Float))
+                return new TokenTypeLSLFloat(original);
+            if(typ == typeof(LSL_String))
+                return new TokenTypeLSLString(original);
+            if(typ == typeof(char))
+                return new TokenTypeChar(original);
+            if(typ == typeof(Exception))
+                return new TokenTypeExc(original);
+
+            throw new Exception("unknown script type " + typ.ToString());
+        }
+
+        public static TokenType FromLSLType(Token original, string typ)
+        {
+            if(typ == "list")
+                return new TokenTypeList(original);
+            if(typ == "rotation")
+                return new TokenTypeRot(original);
+            if(typ == "vector")
+                return new TokenTypeVec(original);
+            if(typ == "float")
+                return new TokenTypeFloat(original);
+            if(typ == "integer")
+                return new TokenTypeInt(original);
+            if(typ == "key")
+                return new TokenTypeKey(original);
+            if(typ == "string")
+                return new TokenTypeStr(original);
+            if(typ == "object")
+                return new TokenTypeObject(original);
+            if(typ == "array")
+                return new TokenTypeArray(original);
+            if(typ == "bool")
+                return new TokenTypeBool(original);
+            if(typ == "void")
+                return new TokenTypeVoid(original);
+            if(typ == "char")
+                return new TokenTypeChar(original);
+            if(typ == "exception")
+                return new TokenTypeExc(original);
+
+            throw new Exception("unknown type " + typ);
+        }
+
+        /**
+         * @brief Estimate the number of bytes of memory taken by one of these
+         *        objects.  For objects with widely varying size, return the
+         *        smallest it can be.
+         */
+        public static int StaticSize(System.Type typ)
+        {
+            if(typ == typeof(LSL_List))
+                return 96;
+            if(typ == typeof(LSL_Rotation))
+                return 80;
+            if(typ == typeof(void))
+                return 0;
+            if(typ == typeof(LSL_Vector))
+                return 72;
+            if(typ == typeof(float))
+                return 8;
+            if(typ == typeof(int))
+                return 8;
+            if(typ == typeof(string))
+                return 40;
+            if(typ == typeof(double))
+                return 8;
+            if(typ == typeof(bool))
+                return 8;
+            if(typ == typeof(XMR_Array))
+                return 96;
+            if(typ == typeof(object))
+                return 32;
+            if(typ == typeof(char))
+                return 2;
+
+            if(typ == typeof(LSL_Integer))
+                return 32;
+            if(typ == typeof(LSL_Float))
+                return 32;
+            if(typ == typeof(LSL_String))
+                return 40;
+
+            throw new Exception("unknown type " + typ.ToString());
+        }
+
+        /**
+         * @brief Return the corresponding system type.
+         */
+        public abstract Type ToSysType();
+
+        /**
+         * @brief Return the equivalent LSL wrapping type.
+         *
+         *  null: normal
+         *  else: LSL-style wrapping, ie, LSL_Integer, LSL_Float, LSL_String
+         *        ToSysType()=System.Int32;  lslWrapping=LSL_Integer
+         *        ToSysType()=System.Float;  lslWrapping=LSL_Float
+         *        ToSysType()=System.String; lslWrapping=LSL_String
+         */
+        public virtual Type ToLSLWrapType()
+        {
+            return null;
+        }
+
+        /**
+         * @brief Assign slots in either the global variable arrays or the script-defined type instance arrays.
+         *        These only need to be implemented for script-visible types, ie, those that a script writer 
+         *        can actually define a variable as.
+         */
+        public virtual void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            throw new Exception("not implemented for " + ToString() + " (" + GetType() + ")");
+        }
+
+        /**
+         * @brief Get heap tracking type.
+         *        null indicates there is no heap tracker for the type.
+         */
+        public virtual Type ToHeapTrackerType()
+        {
+            return null;
+        }
+        public virtual ConstructorInfo GetHeapTrackerCtor()
+        {
+            throw new ApplicationException("no GetHeapTrackerCtor for " + this.GetType());
+        }
+        public virtual void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            throw new ApplicationException("no CallHeapTrackerPopMeth for " + this.GetType());
+        }
+        public virtual void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            throw new ApplicationException("no CallHeapTrackerPushMeth for " + this.GetType());
+        }
+    }
+
+    public class TokenTypeArray: TokenType
+    {
+        private static readonly FieldInfo iarArraysFieldInfo = typeof(XMRInstArrays).GetField("iarArrays");
+
+        public TokenTypeArray(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeArray(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(XMR_Array);
+        }
+        public override string ToString()
+        {
+            return "array";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarArraysFieldInfo;
+            declVar.vTableIndex = arSizes.iasArrays++;
+        }
+    }
+    public class TokenTypeBool: TokenType
+    {
+        public TokenTypeBool(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeBool(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(bool);
+        }
+        public override string ToString()
+        {
+            return "bool";
+        }
+    }
+    public class TokenTypeChar: TokenType
+    {
+        private static readonly FieldInfo iarCharsFieldInfo = typeof(XMRInstArrays).GetField("iarChars");
+
+        public TokenTypeChar(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeChar(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(char);
+        }
+        public override string ToString()
+        {
+            return "char";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarCharsFieldInfo;
+            declVar.vTableIndex = arSizes.iasChars++;
+        }
+    }
+    public class TokenTypeExc: TokenType
+    {
+        private static readonly FieldInfo iarObjectsFieldInfo = typeof(XMRInstArrays).GetField("iarObjects");
+
+        public TokenTypeExc(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeExc(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(Exception);
+        }
+        public override string ToString()
+        {
+            return "exception";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarObjectsFieldInfo;
+            declVar.vTableIndex = arSizes.iasObjects++;
+        }
+    }
+    public class TokenTypeFloat: TokenType
+    {
+        private static readonly FieldInfo iarFloatsFieldInfo = typeof(XMRInstArrays).GetField("iarFloats");
+
+        public TokenTypeFloat(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeFloat(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(double);
+        }
+        public override string ToString()
+        {
+            return "float";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarFloatsFieldInfo;
+            declVar.vTableIndex = arSizes.iasFloats++;
+        }
+    }
+    public class TokenTypeInt: TokenType
+    {
+        private static readonly FieldInfo iarIntegersFieldInfo = typeof(XMRInstArrays).GetField("iarIntegers");
+
+        public TokenTypeInt(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeInt(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(int);
+        }
+        public override string ToString()
+        {
+            return "integer";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarIntegersFieldInfo;
+            declVar.vTableIndex = arSizes.iasIntegers++;
+        }
+    }
+    public class TokenTypeKey: TokenType
+    {
+        private static readonly FieldInfo iarStringsFieldInfo = typeof(XMRInstArrays).GetField("iarStrings");
+
+        public TokenTypeKey(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeKey(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(string);
+        }
+        public override string ToString()
+        {
+            return "key";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarStringsFieldInfo;
+            declVar.vTableIndex = arSizes.iasStrings++;
+        }
+    }
+    public class TokenTypeList: TokenType
+    {
+        private static readonly FieldInfo iarListsFieldInfo = typeof(XMRInstArrays).GetField("iarLists");
+        private static readonly ConstructorInfo htListCtor = typeof(HeapTrackerList).GetConstructor(new Type[] { typeof(XMRInstAbstract) });
+
+        public TokenTypeList(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeList(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(LSL_List);
+        }
+        public override string ToString()
+        {
+            return "list";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarListsFieldInfo;
+            declVar.vTableIndex = arSizes.iasLists++;
+        }
+        public override Type ToHeapTrackerType()
+        {
+            return typeof(HeapTrackerList);
+        }
+        public override ConstructorInfo GetHeapTrackerCtor()
+        {
+            return htListCtor;
+        }
+        public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerList.GenPop(errorAt, ilGen);
+        }
+        public override void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerList.GenPush(errorAt, ilGen);
+        }
+    }
+    public class TokenTypeObject: TokenType
+    {
+        private static readonly FieldInfo iarObjectsFieldInfo = typeof(XMRInstArrays).GetField("iarObjects");
+        private static readonly ConstructorInfo htObjectCtor = typeof(HeapTrackerObject).GetConstructor(new Type[] { typeof(XMRInstAbstract) });
+
+        public TokenTypeObject(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeObject(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(object);
+        }
+        public override string ToString()
+        {
+            return "object";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarObjectsFieldInfo;
+            declVar.vTableIndex = arSizes.iasObjects++;
+        }
+        public override Type ToHeapTrackerType()
+        {
+            return typeof(HeapTrackerObject);
+        }
+        public override ConstructorInfo GetHeapTrackerCtor()
+        {
+            return htObjectCtor;
+        }
+        public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerObject.GenPop(errorAt, ilGen);
+        }
+        public override void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerObject.GenPush(errorAt, ilGen);
+        }
+    }
+    public class TokenTypeRot: TokenType
+    {
+        private static readonly FieldInfo iarRotationsFieldInfo = typeof(XMRInstArrays).GetField("iarRotations");
+
+        public TokenTypeRot(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeRot(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(LSL_Rotation);
+        }
+        public override string ToString()
+        {
+            return "rotation";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarRotationsFieldInfo;
+            declVar.vTableIndex = arSizes.iasRotations++;
+        }
+    }
+    public class TokenTypeStr: TokenType
+    {
+        private static readonly FieldInfo iarStringsFieldInfo = typeof(XMRInstArrays).GetField("iarStrings");
+        private static readonly ConstructorInfo htStringCtor = typeof(HeapTrackerString).GetConstructor(new Type[] { typeof(XMRInstAbstract) });
+
+        public TokenTypeStr(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeStr(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(string);
+        }
+        public override string ToString()
+        {
+            return "string";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarStringsFieldInfo;
+            declVar.vTableIndex = arSizes.iasStrings++;
+        }
+        public override Type ToHeapTrackerType()
+        {
+            return typeof(HeapTrackerString);
+        }
+        public override ConstructorInfo GetHeapTrackerCtor()
+        {
+            return htStringCtor;
+        }
+        public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerString.GenPop(errorAt, ilGen);
+        }
+        public override void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen)
+        {
+            HeapTrackerString.GenPush(errorAt, ilGen);
+        }
+    }
+    public class TokenTypeUndef: TokenType
+    {  // for the 'undef' constant, ie, null object pointer
+        public TokenTypeUndef(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeUndef(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(object);
+        }
+        public override string ToString()
+        {
+            return "undef";
+        }
+    }
+    public class TokenTypeVec: TokenType
+    {
+        private static readonly FieldInfo iarVectorsFieldInfo = typeof(XMRInstArrays).GetField("iarVectors");
+
+        public TokenTypeVec(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeVec(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(LSL_Vector);
+        }
+        public override string ToString()
+        {
+            return "vector";
+        }
+        public override void AssignVarSlot(TokenDeclVar declVar, XMRInstArSizes arSizes)
+        {
+            declVar.vTableArray = iarVectorsFieldInfo;
+            declVar.vTableIndex = arSizes.iasVectors++;
+        }
+    }
+    public class TokenTypeVoid: TokenType
+    {  // used only for function/method return types
+        public TokenTypeVoid(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeVoid(Token original) : base(original) { }
+        public override Type ToSysType()
+        {
+            return typeof(void);
+        }
+        public override string ToString()
+        {
+            return "void";
+        }
+    }
+
+    public class TokenTypeLSLFloat: TokenTypeFloat
+    {
+        public TokenTypeLSLFloat(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeLSLFloat(Token original) : base(original) { }
+        public override Type ToLSLWrapType()
+        {
+            return typeof(LSL_Float);
+        }
+    }
+    public class TokenTypeLSLInt: TokenTypeInt
+    {
+        public TokenTypeLSLInt(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeLSLInt(Token original) : base(original) { }
+        public override Type ToLSLWrapType()
+        {
+            return typeof(LSL_Integer);
+        }
+    }
+    public class TokenTypeLSLKey: TokenTypeKey
+    {
+        public TokenTypeLSLKey(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeLSLKey(Token original) : base(original) { }
+        public override Type ToLSLWrapType()
+        {
+            return typeof(LSL_Key);
+        }
+    }
+    public class TokenTypeLSLString: TokenTypeStr
+    {
+        public TokenTypeLSLString(TokenErrorMessage emsg, string file, int line, int posn) : base(emsg, file, line, posn) { }
+        public TokenTypeLSLString(Token original) : base(original) { }
+        public override Type ToLSLWrapType()
+        {
+            return typeof(LSL_String);
+        }
+    }
+}

+ 1012 - 0
OpenSim/Region/ScriptEngine/YEngine/MMRScriptTypeCast.cs

@@ -0,0 +1,1012 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using OpenSim.Region.ScriptEngine.Yengine;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * @brief Generate script object code to perform type casting
+ */
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    public class TypeCast
+    {
+        private delegate void CastDelegate(IScriptCodeGen scg, Token errorAt);
+
+        private static ConstructorInfo floatConstructorStringInfo = typeof(LSL_Float).GetConstructor(new Type[] { typeof(string) });
+        private static ConstructorInfo integerConstructorStringInfo = typeof(LSL_Integer).GetConstructor(new Type[] { typeof(string) });
+        private static ConstructorInfo lslFloatConstructorInfo = typeof(LSL_Float).GetConstructor(new Type[] { typeof(double) });
+        private static ConstructorInfo lslIntegerConstructorInfo = typeof(LSL_Integer).GetConstructor(new Type[] { typeof(int) });
+        private static ConstructorInfo lslStringConstructorInfo = typeof(LSL_String).GetConstructor(new Type[] { typeof(string) });
+        private static ConstructorInfo rotationConstrucorStringInfo = typeof(LSL_Rotation).GetConstructor(new Type[] { typeof(string) });
+        private static ConstructorInfo vectorConstrucorStringInfo = typeof(LSL_Vector).GetConstructor(new Type[] { typeof(string) });
+        private static FieldInfo lslFloatValueFieldInfo = typeof(LSL_Float).GetField("value");
+        private static FieldInfo lslIntegerValueFieldInfo = typeof(LSL_Integer).GetField("value");
+        private static FieldInfo lslStringValueFieldInfo = typeof(LSL_String).GetField("m_string");
+        private static FieldInfo sdtcITableFieldInfo = typeof(XMRSDTypeClObj).GetField("sdtcITable");
+        private static MethodInfo boolToListMethodInfo = typeof(TypeCast).GetMethod("BoolToList", new Type[] { typeof(bool) });
+        private static MethodInfo boolToStringMethodInfo = typeof(TypeCast).GetMethod("BoolToString", new Type[] { typeof(bool) });
+        private static MethodInfo charToStringMethodInfo = typeof(TypeCast).GetMethod("CharToString", new Type[] { typeof(char) });
+        private static MethodInfo excToStringMethodInfo = typeof(TypeCast).GetMethod("ExceptionToString", new Type[] { typeof(Exception), typeof(XMRInstAbstract) });
+        private static MethodInfo floatToStringMethodInfo = typeof(TypeCast).GetMethod("FloatToString", new Type[] { typeof(double) });
+        private static MethodInfo intToStringMethodInfo = typeof(TypeCast).GetMethod("IntegerToString", new Type[] { typeof(int) });
+        private static MethodInfo keyToBoolMethodInfo = typeof(TypeCast).GetMethod("KeyToBool", new Type[] { typeof(string) });
+        private static MethodInfo listToBoolMethodInfo = typeof(TypeCast).GetMethod("ListToBool", new Type[] { typeof(LSL_List) });
+        private static MethodInfo listToStringMethodInfo = typeof(TypeCast).GetMethod("ListToString", new Type[] { typeof(LSL_List) });
+        private static MethodInfo objectToFloatMethodInfo = typeof(TypeCast).GetMethod("ObjectToFloat", new Type[] { typeof(object) });
+        private static MethodInfo objectToIntegerMethodInfo = typeof(TypeCast).GetMethod("ObjectToInteger", new Type[] { typeof(object) });
+        private static MethodInfo objectToListMethodInfo = typeof(TypeCast).GetMethod("ObjectToList", new Type[] { typeof(object) });
+        private static MethodInfo objectToRotationMethodInfo = typeof(TypeCast).GetMethod("ObjectToRotation", new Type[] { typeof(object) });
+        private static MethodInfo objectToStringMethodInfo = typeof(TypeCast).GetMethod("ObjectToString", new Type[] { typeof(object) });
+        private static MethodInfo objectToVectorMethodInfo = typeof(TypeCast).GetMethod("ObjectToVector", new Type[] { typeof(object) });
+        private static MethodInfo rotationToBoolMethodInfo = typeof(TypeCast).GetMethod("RotationToBool", new Type[] { typeof(LSL_Rotation) });
+        private static MethodInfo rotationToStringMethodInfo = typeof(TypeCast).GetMethod("RotationToString", new Type[] { typeof(LSL_Rotation) });
+        private static MethodInfo stringToBoolMethodInfo = typeof(TypeCast).GetMethod("StringToBool", new Type[] { typeof(string) });
+        private static MethodInfo vectorToBoolMethodInfo = typeof(TypeCast).GetMethod("VectorToBool", new Type[] { typeof(LSL_Vector) });
+        private static MethodInfo vectorToStringMethodInfo = typeof(TypeCast).GetMethod("VectorToString", new Type[] { typeof(LSL_Vector) });
+        private static MethodInfo sdTypeClassCastClass2ClassMethodInfo = typeof(XMRSDTypeClObj).GetMethod("CastClass2Class", new Type[] { typeof(object), typeof(int) });
+        private static MethodInfo sdTypeClassCastIFace2ClassMethodInfo = typeof(XMRSDTypeClObj).GetMethod("CastIFace2Class", new Type[] { typeof(Delegate[]), typeof(int) });
+        private static MethodInfo sdTypeClassCastObj2IFaceMethodInfo = typeof(XMRSDTypeClObj).GetMethod("CastObj2IFace", new Type[] { typeof(object), typeof(string) });
+        private static MethodInfo charToListMethodInfo = typeof(TypeCast).GetMethod("CharToList", new Type[] { typeof(char) });
+        private static MethodInfo excToListMethodInfo = typeof(TypeCast).GetMethod("ExcToList", new Type[] { typeof(Exception) });
+        private static MethodInfo vectorToListMethodInfo = typeof(TypeCast).GetMethod("VectorToList", new Type[] { typeof(LSL_Vector) });
+        private static MethodInfo floatToListMethodInfo = typeof(TypeCast).GetMethod("FloatToList", new Type[] { typeof(double) });
+        private static MethodInfo integerToListMethodInfo = typeof(TypeCast).GetMethod("IntegerToList", new Type[] { typeof(int) });
+        private static MethodInfo rotationToListMethodInfo = typeof(TypeCast).GetMethod("RotationToList", new Type[] { typeof(LSL_Rotation) });
+        private static MethodInfo stringToListMethodInfo = typeof(TypeCast).GetMethod("StringToList", new Type[] { typeof(string) });
+
+        /*
+         * List of all allowed type casts and how to perform the casting.
+         */
+        private static Dictionary<string, CastDelegate> legalTypeCasts = CreateLegalTypeCasts();
+
+        /**
+         * @brief create a dictionary of legal type casts.
+         * Defines what EXPLICIT type casts are allowed in addition to the IMPLICIT ones.
+         * Key is of the form <oldtype> <newtype> for IMPLICIT casting.
+         * Key is of the form <oldtype>*<newtype> for EXPLICIT casting.
+         * Value is a delegate that generates code to perform the type cast.
+         */
+        private static Dictionary<string, CastDelegate> CreateLegalTypeCasts()
+        {
+            Dictionary<string, CastDelegate> ltc = new Dictionary<string, CastDelegate>();
+
+            // IMPLICIT type casts (a space is in middle of the key)
+            // EXPLICIT type casts (an * is in middle of the key)
+            // In general, only mark explicit if it might throw an exception
+            ltc.Add("array object", TypeCastArray2Object);
+            ltc.Add("bool float", TypeCastBool2Float);
+            ltc.Add("bool integer", TypeCastBool2Integer);
+            ltc.Add("bool list", TypeCastBool2List);
+            ltc.Add("bool object", TypeCastBool2Object);
+            ltc.Add("bool string", TypeCastBool2String);
+            ltc.Add("char integer", TypeCastChar2Integer);
+            ltc.Add("char list", TypeCastChar2List);
+            ltc.Add("char object", TypeCastChar2Object);
+            ltc.Add("char string", TypeCastChar2String);
+            ltc.Add("exception list", TypeCastExc2List);
+            ltc.Add("exception object", TypeCastExc2Object);
+            ltc.Add("exception string", TypeCastExc2String);
+            ltc.Add("float bool", TypeCastFloat2Bool);
+            ltc.Add("float integer", TypeCastFloat2Integer);
+            ltc.Add("float list", TypeCastFloat2List);
+            ltc.Add("float object", TypeCastFloat2Object);
+            ltc.Add("float string", TypeCastFloat2String);
+            ltc.Add("integer bool", TypeCastInteger2Bool);
+            ltc.Add("integer char", TypeCastInteger2Char);
+            ltc.Add("integer float", TypeCastInteger2Float);
+            ltc.Add("integer list", TypeCastInteger2List);
+            ltc.Add("integer object", TypeCastInteger2Object);
+            ltc.Add("integer string", TypeCastInteger2String);
+            ltc.Add("list bool", TypeCastList2Bool);
+            ltc.Add("list object", TypeCastList2Object);
+            ltc.Add("list string", TypeCastList2String);
+            ltc.Add("object*array", TypeCastObject2Array);
+            ltc.Add("object*bool", TypeCastObject2Bool);
+            ltc.Add("object*char", TypeCastObject2Char);
+            ltc.Add("object*exception", TypeCastObject2Exc);
+            ltc.Add("object*float", TypeCastObject2Float);
+            ltc.Add("object*integer", TypeCastObject2Integer);
+            ltc.Add("object*list", TypeCastObject2List);
+            ltc.Add("object*rotation", TypeCastObject2Rotation);
+            ltc.Add("object string", TypeCastObject2String);
+            ltc.Add("object*vector", TypeCastObject2Vector);
+            ltc.Add("rotation bool", TypeCastRotation2Bool);
+            ltc.Add("rotation list", TypeCastRotation2List);
+            ltc.Add("rotation object", TypeCastRotation2Object);
+            ltc.Add("rotation string", TypeCastRotation2String);
+            ltc.Add("string bool", TypeCastString2Bool);
+            ltc.Add("string float", TypeCastString2Float);
+            ltc.Add("string integer", TypeCastString2Integer);
+            ltc.Add("string list", TypeCastString2List);
+            ltc.Add("string object", TypeCastString2Object);
+            ltc.Add("string rotation", TypeCastString2Rotation);
+            ltc.Add("string vector", TypeCastString2Vector);
+            ltc.Add("vector bool", TypeCastVector2Bool);
+            ltc.Add("vector list", TypeCastVector2List);
+            ltc.Add("vector object", TypeCastVector2Object);
+            ltc.Add("vector string", TypeCastVector2String);
+
+            return ltc;
+        }
+
+        /**
+         * @brief See if the given type can be cast to the other implicitly.
+         * @param dstType = type being cast to
+         * @param srcType = type being cast from
+         * @returns false: implicit cast not allowed
+         *           true: implicit cast allowed
+         */
+        public static bool IsAssignableFrom(TokenType dstType, TokenType srcType)
+        {
+            /*
+             * Do a 'dry run' of the casting operation, discarding any emits and not printing any errors.
+             * But if the casting tries to print error(s), return false.
+             * Otherwise assume the cast is allowed and return true.
+             */
+            SCGIAF scg = new SCGIAF();
+            scg.ok = true;
+            scg._ilGen = migiaf;
+            CastTopOfStack(scg, null, srcType, dstType, false);
+            return scg.ok;
+        }
+
+        private struct SCGIAF: IScriptCodeGen
+        {
+            public bool ok;
+            public ScriptMyILGen _ilGen;
+
+            // IScriptCodeGen
+            public ScriptMyILGen ilGen
+            {
+                get
+                {
+                    return _ilGen;
+                }
+            }
+            public void ErrorMsg(Token token, string message)
+            {
+                ok = false;
+            }
+            public void PushDefaultValue(TokenType type)
+            {
+            }
+            public void PushXMRInst()
+            {
+            }
+        }
+
+        private static readonly MIGIAF migiaf = new MIGIAF();
+        private struct MIGIAF: ScriptMyILGen
+        {
+            // ScriptMyILGen
+            public string methName
+            {
+                get
+                {
+                    return null;
+                }
+            }
+            public ScriptMyLocal DeclareLocal(Type type, string name)
+            {
+                return null;
+            }
+            public ScriptMyLabel DefineLabel(string name)
+            {
+                return null;
+            }
+            public void BeginExceptionBlock()
+            {
+            }
+            public void BeginCatchBlock(Type excType)
+            {
+            }
+            public void BeginFinallyBlock()
+            {
+            }
+            public void EndExceptionBlock()
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, FieldInfo field)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, Type type)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, MethodInfo method)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, double value)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, float value)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, int value)
+            {
+            }
+            public void Emit(Token errorAt, OpCode opcode, string value)
+            {
+            }
+            public void MarkLabel(ScriptMyLabel myLabel)
+            {
+            }
+        }
+
+        /**
+         * @brief Emit code that converts the top stack item from 'oldType' to 'newType'
+         * @param scg = what script we are compiling
+         * @param errorAt = token used for source location for error messages
+         * @param oldType = type of item currently on the stack
+         * @param newType = type to convert it to
+         * @param explicitAllowed = false: only consider implicit casts
+         *                           true: consider both implicit and explicit casts
+         * @returns with code emitted for conversion (or error message output if not allowed, and stack left unchanged)
+         */
+        public static void CastTopOfStack(IScriptCodeGen scg, Token errorAt, TokenType oldType, TokenType newType, bool explicitAllowed)
+        {
+            CastDelegate castDelegate;
+            string oldString = oldType.ToString();
+            string newString = newType.ToString();
+
+            /*
+             * 'key' -> 'bool' is the only time we care about key being different than string.
+             */
+            if((oldString == "key") && (newString == "bool"))
+            {
+                LSLUnwrap(scg, errorAt, oldType);
+                scg.ilGen.Emit(errorAt, OpCodes.Call, keyToBoolMethodInfo);
+                LSLWrap(scg, errorAt, newType);
+                return;
+            }
+
+            /*
+             * Treat key and string as same type for all other type casts.
+             */
+            if(oldString == "key")
+                oldString = "string";
+            if(newString == "key")
+                newString = "string";
+
+            /*
+             * If the types are the same, there is no conceptual casting needed.
+             * However, there may be wraping/unwraping to/from the LSL wrappers.
+             */
+            if(oldString == newString)
+            {
+                if(oldType.ToLSLWrapType() != newType.ToLSLWrapType())
+                {
+                    LSLUnwrap(scg, errorAt, oldType);
+                    LSLWrap(scg, errorAt, newType);
+                }
+                return;
+            }
+
+            /*
+             * Script-defined classes can be cast up and down the tree.
+             */
+            if((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeClass))
+            {
+                TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
+                TokenDeclSDTypeClass newSDTC = ((TokenTypeSDTypeClass)newType).decl;
+
+                // implicit cast allowed from leaf toward root
+                for(TokenDeclSDTypeClass sdtc = oldSDTC; sdtc != null; sdtc = sdtc.extends)
+                {
+                    if(sdtc == newSDTC)
+                        return;
+                }
+
+                // explicit cast allowed from root toward leaf
+                for(TokenDeclSDTypeClass sdtc = newSDTC; sdtc != null; sdtc = sdtc.extends)
+                {
+                    if(sdtc == oldSDTC)
+                    {
+                        ExplCheck(scg, errorAt, explicitAllowed, oldString, newString);
+                        scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, newSDTC.sdTypeIndex);
+                        scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
+                        return;
+                    }
+                }
+
+                // not on same branch
+                goto illcast;
+            }
+
+            /*
+             * One script-defined interface type cannot be cast to another script-defined interface type, 
+             * unless the old interface declares that it implements the new interface.  That proves that 
+             * the underlying object, no matter what type, implements the new interface.
+             */
+            if((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeInterface))
+            {
+                TokenDeclSDTypeInterface oldDecl = ((TokenTypeSDTypeInterface)oldType).decl;
+                TokenDeclSDTypeInterface newDecl = ((TokenTypeSDTypeInterface)newType).decl;
+                if(!oldDecl.Implements(newDecl))
+                    goto illcast;
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, newType.ToString());
+                scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
+                return;
+            }
+
+            /*
+             * A script-defined class type can be implicitly cast to a script-defined interface type that it 
+             * implements.  The result is an array of delegates that give the class's implementation of the 
+             * various methods defined by the interface.
+             */
+            if((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeInterface))
+            {
+                TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
+                int intfIndex;
+                if(!oldSDTC.intfIndices.TryGetValue(newType.ToString(), out intfIndex))
+                    goto illcast;
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, sdtcITableFieldInfo);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, intfIndex);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate[]));
+                return;
+            }
+
+            /*
+             * A script-defined interface type can be explicitly cast to a script-defined class type by 
+             * extracting the Target property from element 0 of the delegate array that is the interface
+             * object and making sure it casts to the correct script-defined class type.
+             *
+             * But then only if the class type implements the interface type.
+             */
+            if((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeClass))
+            {
+                TokenTypeSDTypeInterface oldSDTI = (TokenTypeSDTypeInterface)oldType;
+                TokenTypeSDTypeClass newSDTC = (TokenTypeSDTypeClass)newType;
+
+                if(!newSDTC.decl.CanCastToIntf(oldSDTI.decl))
+                    goto illcast;
+
+                ExplCheck(scg, errorAt, explicitAllowed, oldString, newString);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, newSDTC.decl.sdTypeIndex);
+                scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastIFace2ClassMethodInfo);
+                return;
+            }
+
+            /*
+             * A script-defined interface type can be implicitly cast to object.
+             */
+            if((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeObject))
+            {
+                return;
+            }
+
+            /*
+             * An object can be explicitly cast to a script-defined interface.
+             */
+            if((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeInterface))
+            {
+                ExplCheck(scg, errorAt, explicitAllowed, oldString, newString);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, newString);
+                scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
+                return;
+            }
+
+            /*
+             * Cast to void is always allowed, such as discarding value from 'i++' or function return value.
+             */
+            if(newType is TokenTypeVoid)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+                return;
+            }
+
+            /*
+             * Cast from undef to object or script-defined type is always allowed.
+             */
+            if((oldType is TokenTypeUndef) &&
+                ((newType is TokenTypeObject) ||
+                 (newType is TokenTypeSDTypeClass) ||
+                 (newType is TokenTypeSDTypeInterface)))
+            {
+                return;
+            }
+
+            /*
+             * Script-defined classes can be implicitly cast to objects.
+             */
+            if((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeObject))
+            {
+                return;
+            }
+
+            /*
+             * Script-defined classes can be explicitly cast from objects and other script-defined classes.
+             * Note that we must manually check that it is the correct SDTypeClass however because as far as 
+             * mono is concerned, all SDTypeClass's are the same.
+             */
+            if((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeClass))
+            {
+                ExplCheck(scg, errorAt, explicitAllowed, oldString, newString);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, ((TokenTypeSDTypeClass)newType).decl.sdTypeIndex);
+                scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
+                return;
+            }
+
+            /*
+             * Delegates can be implicitly cast to/from objects.
+             */
+            if((oldType is TokenTypeSDTypeDelegate) && (newType is TokenTypeObject))
+            {
+                return;
+            }
+            if((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeDelegate))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, newType.ToSysType());
+                return;
+            }
+
+            /*
+             * Some actual conversion is needed, see if it is in table of legal casts.
+             */
+            string key = oldString + " " + newString;
+            if(!legalTypeCasts.TryGetValue(key, out castDelegate))
+            {
+                key = oldString + "*" + newString;
+                if(!legalTypeCasts.TryGetValue(key, out castDelegate))
+                    goto illcast;
+                ExplCheck(scg, errorAt, explicitAllowed, oldString, newString);
+            }
+
+            /*
+             * Ok, output cast.  But make sure it is in native form without any LSL wrapping
+             * before passing to our casting routine.  Then if caller is expecting an LSL-
+             * wrapped value on the stack upon return, wrap it up after our casting.
+             */
+            LSLUnwrap(scg, errorAt, oldType);
+            castDelegate(scg, errorAt);
+            LSLWrap(scg, errorAt, newType);
+            return;
+
+            illcast:
+            scg.ErrorMsg(errorAt, "illegal to cast from " + oldString + " to " + newString);
+            if(!(oldType is TokenTypeVoid))
+                scg.ilGen.Emit(errorAt, OpCodes.Pop);
+            scg.PushDefaultValue(newType);
+        }
+        private static void ExplCheck(IScriptCodeGen scg, Token errorAt, bool explicitAllowed, string oldString, string newString)
+        {
+            if(!explicitAllowed)
+            {
+                scg.ErrorMsg(errorAt, "must explicitly cast from " + oldString + " to " + newString);
+            }
+        }
+
+        /**
+         * @brief If value on the stack is an LSL-style wrapped value, unwrap it.
+         */
+        public static void LSLUnwrap(IScriptCodeGen scg, Token errorAt, TokenType type)
+        {
+            if(type.ToLSLWrapType() == typeof(LSL_Float))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
+            }
+            if(type.ToLSLWrapType() == typeof(LSL_Integer))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
+            }
+            if(type.ToLSLWrapType() == typeof(LSL_String))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslStringValueFieldInfo);
+            }
+        }
+
+        /**
+         * @brief If caller wants the unwrapped value on stack wrapped LSL-style, wrap it.
+         */
+        private static void LSLWrap(IScriptCodeGen scg, Token errorAt, TokenType type)
+        {
+            if(type.ToLSLWrapType() == typeof(LSL_Float))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslFloatConstructorInfo);
+            }
+            if(type.ToLSLWrapType() == typeof(LSL_Integer))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslIntegerConstructorInfo);
+            }
+            if(type.ToLSLWrapType() == typeof(LSL_String))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslStringConstructorInfo);
+            }
+        }
+
+        /**
+         * @brief These routines output code to perform casting.
+         *        They can assume there are no LSL wrapped values on input
+         *        and they should not output an LSL wrapped value.
+         */
+        private static void TypeCastArray2Object(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastBool2Float(IScriptCodeGen scg, Token errorAt)
+        {
+            if(typeof(double) == typeof(float))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Conv_R4);
+            }
+            else if(typeof(double) == typeof(double))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Conv_R8);
+            }
+            else
+            {
+                throw new Exception("unknown type");
+            }
+        }
+        private static void TypeCastBool2Integer(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastBool2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(bool));
+        }
+        private static void TypeCastChar2Integer(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastChar2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, charToListMethodInfo);
+        }
+        private static void TypeCastChar2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(char));
+        }
+        private static void TypeCastChar2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, charToStringMethodInfo);
+        }
+        private static void TypeCastExc2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, excToListMethodInfo);
+        }
+        private static void TypeCastExc2Object(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastExc2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.PushXMRInst();
+            scg.ilGen.Emit(errorAt, OpCodes.Call, excToStringMethodInfo);
+        }
+        private static void TypeCastFloat2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_R4, 0.0f);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+        }
+        private static void TypeCastFloat2Integer(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Conv_I4);
+        }
+        private static void TypeCastFloat2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(double));
+        }
+        private static void TypeCastInteger2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
+            scg.ilGen.Emit(errorAt, OpCodes.Ceq);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1);
+            scg.ilGen.Emit(errorAt, OpCodes.Xor);
+        }
+        private static void TypeCastInteger2Char(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastInteger2Float(IScriptCodeGen scg, Token errorAt)
+        {
+            if(typeof(double) == typeof(float))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Conv_R4);
+            }
+            else if(typeof(double) == typeof(double))
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Conv_R8);
+            }
+            else
+            {
+                throw new Exception("unknown type");
+            }
+        }
+        private static void TypeCastInteger2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(int));
+        }
+        private static void TypeCastList2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, listToBoolMethodInfo);
+        }
+        private static void TypeCastList2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            if(typeof(LSL_List).IsValueType)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(LSL_List));
+            }
+        }
+        private static void TypeCastObject2Array(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(XMR_Array));
+        }
+        private static void TypeCastObject2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Unbox_Any, typeof(bool));
+        }
+        private static void TypeCastObject2Char(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Unbox_Any, typeof(char));
+        }
+        private static void TypeCastObject2Exc(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(Exception));
+        }
+        private static void TypeCastObject2Float(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, objectToFloatMethodInfo);
+        }
+        private static void TypeCastObject2Integer(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, objectToIntegerMethodInfo);
+        }
+        private static void TypeCastObject2List(IScriptCodeGen scg, Token errorAt)
+        {
+            if(typeof(LSL_List).IsValueType)
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Call, objectToListMethodInfo);
+            }
+            else
+            {
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(LSL_List));
+            }
+        }
+        private static void TypeCastObject2Rotation(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, objectToRotationMethodInfo);
+        }
+        private static void TypeCastObject2Vector(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, objectToVectorMethodInfo);
+        }
+        private static void TypeCastRotation2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, rotationToBoolMethodInfo);
+        }
+        private static void TypeCastRotation2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(LSL_Rotation));
+        }
+        private static void TypeCastString2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringToBoolMethodInfo);
+        }
+        private static void TypeCastString2Object(IScriptCodeGen scg, Token errorAt)
+        {
+        }
+        private static void TypeCastString2Rotation(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, rotationConstrucorStringInfo);
+        }
+        private static void TypeCastString2Vector(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, vectorConstrucorStringInfo);
+        }
+        private static void TypeCastVector2Bool(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, vectorToBoolMethodInfo);
+        }
+        private static void TypeCastVector2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, vectorToListMethodInfo);
+        }
+        private static void TypeCastVector2Object(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(LSL_Vector));
+        }
+        private static void TypeCastBool2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, boolToListMethodInfo);
+        }
+        private static void TypeCastBool2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, boolToStringMethodInfo);
+        }
+        private static void TypeCastFloat2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, floatToListMethodInfo);
+        }
+        private static void TypeCastFloat2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, floatToStringMethodInfo);
+        }
+        private static void TypeCastInteger2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, integerToListMethodInfo);
+        }
+        private static void TypeCastInteger2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, intToStringMethodInfo);
+        }
+        private static void TypeCastList2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, listToStringMethodInfo);
+        }
+        private static void TypeCastObject2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, objectToStringMethodInfo);
+        }
+        private static void TypeCastRotation2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, rotationToListMethodInfo);
+        }
+        private static void TypeCastRotation2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, rotationToStringMethodInfo);
+        }
+        private static void TypeCastString2Float(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, floatConstructorStringInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
+        }
+        private static void TypeCastString2Integer(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Newobj, integerConstructorStringInfo);
+            scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
+        }
+        private static void TypeCastString2List(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, stringToListMethodInfo);
+        }
+        private static void TypeCastVector2String(IScriptCodeGen scg, Token errorAt)
+        {
+            scg.ilGen.Emit(errorAt, OpCodes.Call, vectorToStringMethodInfo);
+        }
+
+        /*
+         * Because the calls are funky, let the compiler handle them.
+         */
+        public static bool RotationToBool(LSL_Rotation x)
+        {
+            return !x.Equals(ScriptBaseClass.ZERO_ROTATION);
+        }
+        public static bool StringToBool(string x)
+        {
+            return x.Length > 0;
+        }
+        public static bool VectorToBool(LSL_Vector x)
+        {
+            return !x.Equals(ScriptBaseClass.ZERO_VECTOR);
+        }
+        public static string BoolToString(bool x)
+        {
+            return x ? "1" : "0";
+        }
+        public static string CharToString(char x)
+        {
+            return x.ToString();
+        }
+        public static string FloatToString(double x)
+        {
+            return x.ToString("0.000000");
+        }
+        public static string IntegerToString(int x)
+        {
+            return x.ToString();
+        }
+        public static bool KeyToBool(string x)
+        {
+            return (x != "") && (x != ScriptBaseClass.NULL_KEY);
+        }
+        public static bool ListToBool(LSL_List x)
+        {
+            return x.Length != 0;
+        }
+        public static string ListToString(LSL_List x)
+        {
+            return x.ToString();
+        }
+        public static string ObjectToString(object x)
+        {
+            return (x == null) ? null : x.ToString();
+        }
+        public static string RotationToString(LSL_Rotation x)
+        {
+            return x.ToString();
+        }
+        public static string VectorToString(LSL_Vector x)
+        {
+            return x.ToString();
+        }
+        public static LSL_List BoolToList(bool b)
+        {
+            return new LSL_List(new object[] { new LSL_Integer(b ? 1 : 0) });
+        }
+        public static LSL_List CharToList(char c)
+        {
+            return new LSL_List(new object[] { new LSL_Integer(c) });
+        }
+        public static LSL_List ExcToList(Exception e)
+        {
+            return new LSL_List(new object[] { e });
+        }
+        public static LSL_List VectorToList(LSL_Vector v)
+        {
+            return new LSL_List(new object[] { v });
+        }
+        public static LSL_List FloatToList(double f)
+        {
+            return new LSL_List(new object[] { new LSL_Float(f) });
+        }
+        public static LSL_List IntegerToList(int i)
+        {
+            return new LSL_List(new object[] { new LSL_Integer(i) });
+        }
+        public static LSL_List RotationToList(LSL_Rotation r)
+        {
+            return new LSL_List(new object[] { r });
+        }
+        public static LSL_List StringToList(string s)
+        {
+            return new LSL_List(new object[] { new LSL_String(s) });
+        }
+
+        public static double ObjectToFloat(object x)
+        {
+            if(x is LSL_String)
+                return double.Parse(((LSL_String)x).m_string);
+            if(x is string)
+                return double.Parse((string)x);
+            if(x is LSL_Float)
+                return (double)(LSL_Float)x;
+            if(x is LSL_Integer)
+                return (double)(int)(LSL_Integer)x;
+            if(x is int)
+                return (double)(int)x;
+            return (double)x;
+        }
+
+        public static int ObjectToInteger(object x)
+        {
+            if(x is LSL_String)
+                return int.Parse(((LSL_String)x).m_string);
+            if(x is string)
+                return int.Parse((string)x);
+            if(x is LSL_Integer)
+                return (int)(LSL_Integer)x;
+            return (int)x;
+        }
+
+        public static LSL_List ObjectToList(object x)
+        {
+            return (LSL_List)x;
+        }
+
+        public static LSL_Rotation ObjectToRotation(object x)
+        {
+            if(x is LSL_String)
+                return new LSL_Rotation(((LSL_String)x).m_string);
+            if(x is string)
+                return new LSL_Rotation((string)x);
+            return (LSL_Rotation)x;
+        }
+
+        public static LSL_Vector ObjectToVector(object x)
+        {
+            if(x is LSL_String)
+                return new LSL_Vector(((LSL_String)x).m_string);
+            if(x is string)
+                return new LSL_Vector((string)x);
+            return (LSL_Vector)x;
+        }
+
+        public static string ExceptionToString(Exception x, XMRInstAbstract inst)
+        {
+            return XMRInstAbstract.xmrExceptionTypeName(x) + ": " + XMRInstAbstract.xmrExceptionMessage(x) +
+                "\n" + inst.xmrExceptionStackTrace(x);
+        }
+
+        /*
+         * These are used by event handler entrypoints to remove any LSL wrapping
+         * from the argument list and return the unboxed/unwrapped value.
+         */
+        public static double EHArgUnwrapFloat(object x)
+        {
+            if(x is LSL_Float)
+                return (double)(LSL_Float)x;
+            return (double)x;
+        }
+
+        public static int EHArgUnwrapInteger(object x)
+        {
+            if(x is LSL_Integer)
+                return (int)(LSL_Integer)x;
+            return (int)x;
+        }
+
+        public static LSL_Rotation EHArgUnwrapRotation(object x)
+        {
+            if(x is OpenMetaverse.Quaternion)
+            {
+                OpenMetaverse.Quaternion q = (OpenMetaverse.Quaternion)x;
+                return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
+            }
+            return (LSL_Rotation)x;
+        }
+
+        public static string EHArgUnwrapString(object x)
+        {
+            if(x is LSL_Key)
+                return (string)(LSL_Key)x;
+            if(x is LSL_String)
+                return (string)(LSL_String)x;
+            return (string)x;
+        }
+
+        public static LSL_Vector EHArgUnwrapVector(object x)
+        {
+            if(x is OpenMetaverse.Vector3)
+            {
+                OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)x;
+                return new LSL_Vector(v.X, v.Y, v.Z);
+            }
+            return (LSL_Vector)x;
+        }
+    }
+}

+ 158 - 95
OpenSim/Region/ScriptEngine/XMREngine/MMRScriptVarDict.cs → OpenSim/Region/ScriptEngine/YEngine/MMRScriptVarDict.cs

@@ -33,63 +33,80 @@ using System.Collections.Generic;
  * @brief Collection of variable/function/method definitions
  */
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
-    public class VarDict : IEnumerable {
+    public class VarDict: IEnumerable
+    {
         public VarDict outerVarDict;            // next outer VarDict to search
         public TokenDeclSDTypeClass thisClass;  // this VarDict is for members of thisClass
 
-        private struct ArgTypes {
+        private struct ArgTypes
+        {
             public TokenType[] argTypes;
 
-            public bool CanBeCalledBy (TokenType[] calledBy)
+            public bool CanBeCalledBy(TokenType[] calledBy)
             {
-                if ((argTypes == null) && (calledBy == null)) return true;
-                if ((argTypes == null) || (calledBy == null)) return false;
-                if (argTypes.Length != calledBy.Length) return false;
-                for (int i = argTypes.Length; -- i >= 0;) {
-                    if (!TypeCast.IsAssignableFrom (argTypes[i], calledBy[i])) return false;
+                if((argTypes == null) && (calledBy == null))
+                    return true;
+                if((argTypes == null) || (calledBy == null))
+                    return false;
+                if(argTypes.Length != calledBy.Length)
+                    return false;
+                for(int i = argTypes.Length; --i >= 0;)
+                {
+                    if(!TypeCast.IsAssignableFrom(argTypes[i], calledBy[i]))
+                        return false;
                 }
                 return true;
             }
 
-            public override bool Equals (Object that)
+            public override bool Equals(Object that)
             {
-                if (that == null) return false;
-                if (that.GetType () != typeof (ArgTypes)) return false;
+                if(that == null)
+                    return false;
+                if(that.GetType() != typeof(ArgTypes))
+                    return false;
                 TokenType[] at = this.argTypes;
                 TokenType[] bt = ((ArgTypes)that).argTypes;
-                if ((at == null) && (bt == null)) return true;
-                if ((at == null) || (bt == null)) return false;
-                if (at.Length != bt.Length) return false;
-                for (int i = at.Length; -- i >= 0;) {
-                    if (at[i].ToString () != bt[i].ToString ()) return false;
+                if((at == null) && (bt == null))
+                    return true;
+                if((at == null) || (bt == null))
+                    return false;
+                if(at.Length != bt.Length)
+                    return false;
+                for(int i = at.Length; --i >= 0;)
+                {
+                    if(at[i].ToString() != bt[i].ToString())
+                        return false;
                 }
                 return true;
             }
 
-            public override int GetHashCode ()
+            public override int GetHashCode()
             {
                 TokenType[] at = this.argTypes;
-                if (at == null) return -1;
+                if(at == null)
+                    return -1;
                 int hc = 0;
-                for (int i = at.Length; -- i >= 0;) {
+                for(int i = at.Length; --i >= 0;)
+                {
                     int c = (hc < 0) ? 1 : 0;
-                    hc  = hc * 2 + c;
-                    hc ^= at[i].ToString ().GetHashCode ();
+                    hc = hc * 2 + c;
+                    hc ^= at[i].ToString().GetHashCode();
                 }
                 return hc;
             }
         }
 
-        private struct TDVEntry {
+        private struct TDVEntry
+        {
             public int count;
             public TokenDeclVar var;
         }
 
         private bool isFrozen = false;
         private bool locals;
-        private Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master = new Dictionary<string, Dictionary<ArgTypes, TDVEntry>> ();
+        private Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master = new Dictionary<string, Dictionary<ArgTypes, TDVEntry>>();
         private int count = 0;
         private VarDict frozenLocals = null;
 
@@ -98,7 +115,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param locals = false: cannot be frozen, allows forward references
          *                  true: can be frozen, thus forbidding forward references
          */
-        public VarDict (bool locals)
+        public VarDict(bool locals)
         {
             this.locals = locals;
         }
@@ -106,19 +123,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Add new variable to the dictionary.
          */
-        public bool AddEntry (TokenDeclVar var)
+        public bool AddEntry(TokenDeclVar var)
         {
-            if (isFrozen) {
-                throw new Exception ("var dict is frozen");
+            if(isFrozen)
+            {
+                throw new Exception("var dict is frozen");
             }
 
             /*
              * Make sure we have a sub-dictionary based on the bare name (ie, no signature)
              */
             Dictionary<ArgTypes, TDVEntry> typedic;
-            if (!master.TryGetValue (var.name.val, out typedic)) {
-                typedic = new Dictionary<ArgTypes, TDVEntry> ();
-                master.Add (var.name.val, typedic);
+            if(!master.TryGetValue(var.name.val, out typedic))
+            {
+                typedic = new Dictionary<ArgTypes, TDVEntry>();
+                master.Add(var.name.val, typedic);
             }
 
             /*
@@ -127,41 +146,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
              * Methods always have a non-null argument list, even if only 0 entries long.
              */
             ArgTypes types;
-            types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes (var.argDecl.types);
-            if (typedic.ContainsKey (types)) return false;
+            types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes(var.argDecl.types);
+            if(typedic.ContainsKey(types))
+                return false;
 
             /*
              * It is unique, add to its name-specific sub-dictionary.
              */
             TDVEntry entry;
-            entry.count = ++ count;
-            entry.var   = var;
-            typedic.Add (types, entry);
+            entry.count = ++count;
+            entry.var = var;
+            typedic.Add(types, entry);
             return true;
         }
 
-        public int Count { get { return count; } }
+        public int Count
+        {
+            get
+            {
+                return count;
+            }
+        }
 
         /**
          * @brief If this is not a local variable frame, just return the frame as is.
          *        If this is a local variable frame, return a version that is frozen,
          *        ie, one that does not contain any future additions.
          */
-        public VarDict FreezeLocals ()
+        public VarDict FreezeLocals()
         {
             /*
              * If not local var frame, return original frame as is.
              * This will allow forward references as the future additions
              * will be seen by lookups done in this dictionary.
              */
-            if (!locals) return this;
+            if(!locals)
+                return this;
 
             /*
              * If local var frame, return a copy frozen at this point.
              * This disallows forward referenes as those future additions
              * will not be seen by lookups done in the frozen dictionary.
              */
-            if ((frozenLocals == null) || (frozenLocals.count != this.count)) {
+            if((frozenLocals == null) || (frozenLocals.count != this.count))
+            {
 
                 /*
                  * Make a copy of the current var dictionary frame.
@@ -169,12 +197,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                  * contain additions made after this point, those additions
                  * will have a count .gt. frozen count and will be ignored.
                  */
-                frozenLocals = new VarDict (true);
+                frozenLocals = new VarDict(true);
 
                 frozenLocals.outerVarDict = this.outerVarDict;
-                frozenLocals.thisClass    = this.thisClass;
-                frozenLocals.master       = this.master;
-                frozenLocals.count        = this.count;
+                frozenLocals.thisClass = this.thisClass;
+                frozenLocals.master = this.master;
+                frozenLocals.count = this.count;
                 frozenLocals.frozenLocals = frozenLocals;
 
                 /*
@@ -196,23 +224,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *          else: list of matching functions/variables
          *                for variables, always of length 1
          */
-        private List<TokenDeclVar> found = new List<TokenDeclVar> ();
-        public TokenDeclVar[] FindCallables (string name, TokenType[] argTypes)
+        private List<TokenDeclVar> found = new List<TokenDeclVar>();
+        public TokenDeclVar[] FindCallables(string name, TokenType[] argTypes)
         {
-            argTypes = KeyTypesToStringTypes (argTypes);
-            TokenDeclVar var = FindExact (name, argTypes);
-            if (var != null) return new TokenDeclVar[] { var };
+            argTypes = KeyTypesToStringTypes(argTypes);
+            TokenDeclVar var = FindExact(name, argTypes);
+            if(var != null)
+                return new TokenDeclVar[] { var };
 
             Dictionary<ArgTypes, TDVEntry> typedic;
-            if (!master.TryGetValue (name, out typedic)) return null;
+            if(!master.TryGetValue(name, out typedic))
+                return null;
 
-            found.Clear ();
-            foreach (KeyValuePair<ArgTypes, TDVEntry> kvp in typedic) {
-                if ((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy (argTypes)) {
-                    found.Add (kvp.Value.var);
+            found.Clear();
+            foreach(KeyValuePair<ArgTypes, TDVEntry> kvp in typedic)
+            {
+                if((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy(argTypes))
+                {
+                    found.Add(kvp.Value.var);
                 }
             }
-            return (found.Count > 0) ? found.ToArray () : null;
+            return (found.Count > 0) ? found.ToArray() : null;
         }
 
         /**
@@ -223,19 +255,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @returns null: no matching function/variable found
          *          else: the matching function/variable
          */
-        public TokenDeclVar FindExact (string name, TokenType[] argTypes)
+        public TokenDeclVar FindExact(string name, TokenType[] argTypes)
         {
             /*
              * Look for list of stuff that matches the given name.
              */
             Dictionary<ArgTypes, TDVEntry> typedic;
-            if (!master.TryGetValue (name, out typedic)) return null;
+            if(!master.TryGetValue(name, out typedic))
+                return null;
 
             /*
              * Loop through all fields/methods declared by that name, regardless of arg signature.
              */
-            foreach (TDVEntry entry in typedic.Values) {
-                if (entry.count > this.count) continue;
+            foreach(TDVEntry entry in typedic.Values)
+            {
+                if(entry.count > this.count)
+                    continue;
                 TokenDeclVar var = entry.var;
 
                 /*
@@ -248,12 +283,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 /*
                  * Convert any key args to string args.
                  */
-                declArgs = KeyTypesToStringTypes (declArgs);
+                declArgs = KeyTypesToStringTypes(declArgs);
 
                 /*
                  * If both are null, they are signature-less (ie, both are fields), and so match.
                  */
-                if ((declArgs == null) && (argTypes == null)) return var;
+                if((declArgs == null) && (argTypes == null))
+                    return var;
 
                 /*
                  * If calling a delegate, it is a match, regardless of delegate arg types.
@@ -261,29 +297,38 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                  * trying to cast the arguments to the delegate arg types.
                  * We don't allow overloading same field name with different delegate types.
                  */
-                if ((declArgs == null) && (argTypes != null)) {
+                if((declArgs == null) && (argTypes != null))
+                {
                     TokenType fieldType = var.type;
-                    if (fieldType is TokenTypeSDTypeDelegate) return var;
+                    if(fieldType is TokenTypeSDTypeDelegate)
+                        return var;
                 }
 
                 /*
                  * If not both null, no match, keep looking.
                  */
-                if ((declArgs == null) || (argTypes == null)) continue;
+                if((declArgs == null) || (argTypes == null))
+                    continue;
 
                 /*
                  * Both not null, match argument types to make sure we have correct overload.
                  */
                 int i = declArgs.Length;
-                if (i != argTypes.Length) continue;
-                while (-- i >= 0) {
-                    string da = declArgs[i].ToString ();
-                    string ga = argTypes[i].ToString ();
-                    if (da == "key") da = "string";
-                    if (ga == "key") ga = "string";
-                    if (da != ga) break;
+                if(i != argTypes.Length)
+                    continue;
+                while(--i >= 0)
+                {
+                    string da = declArgs[i].ToString();
+                    string ga = argTypes[i].ToString();
+                    if(da == "key")
+                        da = "string";
+                    if(ga == "key")
+                        ga = "string";
+                    if(da != ga)
+                        break;
                 }
-                if (i < 0) return var;
+                if(i < 0)
+                    return var;
             }
 
             /*
@@ -299,20 +344,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param argTypes = argument types as declared in source code
          * @returns argTypes with any key replaced by string
          */
-        private static TokenType[] KeyTypesToStringTypes (TokenType[] argTypes)
+        private static TokenType[] KeyTypesToStringTypes(TokenType[] argTypes)
         {
-            if (argTypes != null) {
+            if(argTypes != null)
+            {
                 int i;
                 int nats = argTypes.Length;
-                for (i = nats; -- i >= 0;) {
-                    if (argTypes[i] is TokenTypeKey) break;
+                for(i = nats; --i >= 0;)
+                {
+                    if(argTypes[i] is TokenTypeKey)
+                        break;
                 }
-                if (i >= 0) {
+                if(i >= 0)
+                {
                     TokenType[] at = new TokenType[nats];
-                    for (i = nats; -- i >= 0;) {
+                    for(i = nats; --i >= 0;)
+                    {
                         at[i] = argTypes[i];
-                        if (argTypes[i] is TokenTypeKey) {
-                            at[i] = new TokenTypeStr (argTypes[i]);
+                        if(argTypes[i] is TokenTypeKey)
+                        {
+                            at[i] = new TokenTypeStr(argTypes[i]);
                         }
                     }
                     return at;
@@ -324,48 +375,60 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         // foreach goes through all the TokenDeclVars that were added
 
         // IEnumerable
-        public IEnumerator GetEnumerator ()
+        public IEnumerator GetEnumerator()
         {
-            return new VarDictEnumerator (this.master, this.count);
+            return new VarDictEnumerator(this.master, this.count);
         }
 
-        private class VarDictEnumerator : IEnumerator {
+        private class VarDictEnumerator: IEnumerator
+        {
             private IEnumerator masterEnum;
             private IEnumerator typedicEnum;
             private int count;
 
-            public VarDictEnumerator (Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master, int count)
+            public VarDictEnumerator(Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master, int count)
             {
-                masterEnum = master.Values.GetEnumerator ();
+                masterEnum = master.Values.GetEnumerator();
                 this.count = count;
             }
 
             // IEnumerator
-            public void Reset ()
+            public void Reset()
             {
-                masterEnum.Reset ();
+                masterEnum.Reset();
                 typedicEnum = null;
             }
 
             // IEnumerator
-            public bool MoveNext ()
+            public bool MoveNext()
             {
-                while (true) {
-                    if (typedicEnum != null) {
-                        while (typedicEnum.MoveNext ()) {
-                            if (((TDVEntry)typedicEnum.Current).count <= this.count) return true;
+                while(true)
+                {
+                    if(typedicEnum != null)
+                    {
+                        while(typedicEnum.MoveNext())
+                        {
+                            if(((TDVEntry)typedicEnum.Current).count <= this.count)
+                                return true;
                         }
                         typedicEnum = null;
                     }
-                    if (!masterEnum.MoveNext ()) return false;
+                    if(!masterEnum.MoveNext())
+                        return false;
                     Dictionary<ArgTypes, TDVEntry> ctd;
                     ctd = (Dictionary<ArgTypes, TDVEntry>)masterEnum.Current;
-                    typedicEnum = ctd.Values.GetEnumerator ();
+                    typedicEnum = ctd.Values.GetEnumerator();
                 }
             }
 
             // IEnumerator
-            public object Current { get { return ((TDVEntry)typedicEnum.Current).var; } }
+            public object Current
+            {
+                get
+                {
+                    return ((TDVEntry)typedicEnum.Current).var;
+                }
+            }
         }
     }
 }

+ 223 - 161
OpenSim/Region/ScriptEngine/XMREngine/XMRArray.cs → OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs

@@ -40,12 +40,13 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
 // This class exists in the main app domain
 //
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /**
      * @brief Array objects.
      */
-    public class XMR_Array {
+    public class XMR_Array
+    {
         private const int EMPTYHEAP = 64;
         private const int ENTRYHEAP = 24;
 
@@ -53,36 +54,40 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                                                               // false: array[0..arrayValid-1] is all there is
         private SortedDictionary<object, object> dnary;
         private SortedDictionary<object, object>.Enumerator enumr;
-                                                              // enumerator used to fill 'array' past arrayValid to end of dictionary
+        // enumerator used to fill 'array' past arrayValid to end of dictionary
         private int arrayValid;                               // number of elements in 'array' that have been filled in
         private KeyValuePair<object, object>[] array;         // list of kvp's that have been returned by ForEach() since last modification
         private XMRInstAbstract inst;                         // script instance debited with heap use
         private int heapUse;                                  // current heap use debit amount
 
-        public static TokenTypeSDTypeDelegate countDelegate = new TokenTypeSDTypeDelegate (new TokenTypeInt    (null), new TokenType[0]);
-        public static TokenTypeSDTypeDelegate clearDelegate = new TokenTypeSDTypeDelegate (new TokenTypeVoid   (null), new TokenType[0]);
-        public static TokenTypeSDTypeDelegate indexDelegate = new TokenTypeSDTypeDelegate (new TokenTypeObject (null), new TokenType[] { new TokenTypeInt (null) });
-        public static TokenTypeSDTypeDelegate valueDelegate = new TokenTypeSDTypeDelegate (new TokenTypeObject (null), new TokenType[] { new TokenTypeInt (null) });
+        public static TokenTypeSDTypeDelegate countDelegate = new TokenTypeSDTypeDelegate(new TokenTypeInt(null), new TokenType[0]);
+        public static TokenTypeSDTypeDelegate clearDelegate = new TokenTypeSDTypeDelegate(new TokenTypeVoid(null), new TokenType[0]);
+        public static TokenTypeSDTypeDelegate indexDelegate = new TokenTypeSDTypeDelegate(new TokenTypeObject(null), new TokenType[] { new TokenTypeInt(null) });
+        public static TokenTypeSDTypeDelegate valueDelegate = new TokenTypeSDTypeDelegate(new TokenTypeObject(null), new TokenType[] { new TokenTypeInt(null) });
 
-        public XMR_Array (XMRInstAbstract inst)
+        public XMR_Array(XMRInstAbstract inst)
         {
             this.inst = inst;
-            dnary = new SortedDictionary<object, object> (XMRArrayKeyComparer.singleton);
-            heapUse = inst.UpdateHeapUse (0, EMPTYHEAP);
+            dnary = new SortedDictionary<object, object>(XMRArrayKeyComparer.singleton);
+            heapUse = inst.UpdateHeapUse(0, EMPTYHEAP);
         }
 
-        ~XMR_Array ()
+        ~XMR_Array()
         {
-            heapUse = inst.UpdateHeapUse (heapUse, 0);
+            heapUse = inst.UpdateHeapUse(heapUse, 0);
         }
 
-        public static TokenType GetRValType (TokenName name)
+        public static TokenType GetRValType(TokenName name)
         {
-            if (name.val == "count") return new TokenTypeInt (name);
-            if (name.val == "clear") return clearDelegate;
-            if (name.val == "index") return indexDelegate;
-            if (name.val == "value") return valueDelegate;
-            return new TokenTypeVoid (name);
+            if(name.val == "count")
+                return new TokenTypeInt(name);
+            if(name.val == "clear")
+                return clearDelegate;
+            if(name.val == "index")
+                return indexDelegate;
+            if(name.val == "value")
+                return valueDelegate;
+            return new TokenTypeVoid(name);
         }
 
         /**
@@ -93,44 +98,51 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public object GetByKey(object key)
         {
             object val;
-            key = FixKey (key);
-            if (!dnary.TryGetValue (key, out val)) val = null;
+            key = FixKey(key);
+            if(!dnary.TryGetValue(key, out val))
+                val = null;
             return val;
         }
 
         public void SetByKey(object key, object value)
         {
-            key = FixKey (key);
+            key = FixKey(key);
 
             /*
              * Update heap use throwing an exception on failure
              * before making any changes to the array.
              */
-            int keysize = HeapTrackerObject.Size (key);
+            int keysize = HeapTrackerObject.Size(key);
             int newheapuse = heapUse;
             object oldval;
-            if (dnary.TryGetValue (key, out oldval)) {
-                newheapuse -= keysize + HeapTrackerObject.Size (oldval);
+            if(dnary.TryGetValue(key, out oldval))
+            {
+                newheapuse -= keysize + HeapTrackerObject.Size(oldval);
             }
-            if (value != null) {
-                newheapuse += keysize + HeapTrackerObject.Size (value);
+            if(value != null)
+            {
+                newheapuse += keysize + HeapTrackerObject.Size(value);
             }
-            heapUse = inst.UpdateHeapUse (heapUse, newheapuse);
+            heapUse = inst.UpdateHeapUse(heapUse, newheapuse);
 
             /*
              * Save new value in array, replacing one of same key if there.
              * null means remove the value, ie, script did array[key] = undef.
              */
-            if (value != null) {
+            if(value != null)
+            {
                 dnary[key] = value;
-            } else {
-                dnary.Remove (key);
+            }
+            else
+            {
+                dnary.Remove(key);
 
                 /*
                  * Shrink the enumeration array, but always leave at least one element.
                  */
-                if ((array != null) && (dnary.Count < array.Length / 2)) {
-                    Array.Resize<KeyValuePair<object, object>> (ref array, array.Length / 2);
+                if((array != null) && (dnary.Count < array.Length / 2))
+                {
+                    Array.Resize<KeyValuePair<object, object>>(ref array, array.Length / 2);
                 }
             }
 
@@ -148,44 +160,48 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *        the C# runtime can't convert a null to a value type, and throws an exception.
          *        But for any reference type (array, key, etc) we must manually check for null.
          */
-        public static XMR_Array Obj2Array (object obj)
+        public static XMR_Array Obj2Array(object obj)
         {
-            if (obj == null) throw new NullReferenceException ();
+            if(obj == null)
+                throw new NullReferenceException();
             return (XMR_Array)obj;
         }
-        public static LSL_Key Obj2Key (object obj)
+        public static LSL_Key Obj2Key(object obj)
         {
-            if (obj == null) throw new NullReferenceException ();
+            if(obj == null)
+                throw new NullReferenceException();
             return (LSL_Key)obj;
         }
-        public static LSL_List Obj2List (object obj)
+        public static LSL_List Obj2List(object obj)
         {
-            if (obj == null) throw new NullReferenceException ();
+            if(obj == null)
+                throw new NullReferenceException();
             return (LSL_List)obj;
         }
-        public static LSL_String Obj2String (object obj)
+        public static LSL_String Obj2String(object obj)
         {
-            if (obj == null) throw new NullReferenceException ();
-            return obj.ToString ();
+            if(obj == null)
+                throw new NullReferenceException();
+            return obj.ToString();
         }
 
         /**
          * @brief remove all elements from the array.
          *        sets everything to its 'just constructed' state.
          */
-        public void __pub_clear ()
+        public void __pub_clear()
         {
-            heapUse = inst.UpdateHeapUse (heapUse, EMPTYHEAP);
-            dnary.Clear ();
+            heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP);
+            dnary.Clear();
             enumrValid = false;
             arrayValid = 0;
-            array      = null;
+            array = null;
         }
 
         /**
          * @brief return number of elements in the array.
          */
-        public int __pub_count ()
+        public int __pub_count()
         {
             return dnary.Count;
         }
@@ -196,9 +212,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @returns null: array doesn't have that many elements
          *          else: index (key) for that element
          */
-        public object __pub_index (int number)
+        public object __pub_index(int number)
         {
-            return ForEach (number) ? UnfixKey (array[number].Key) : null;
+            return ForEach(number) ? UnfixKey(array[number].Key) : null;
         }
 
         /**
@@ -207,9 +223,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @returns null: array doesn't have that many elements
          *          else: value for that element
          */
-        public object __pub_value (int number)
+        public object __pub_value(int number)
         {
-            return ForEach (number) ? array[number].Value : null;
+            return ForEach(number) ? array[number].Value : null;
         }
 
         /**
@@ -218,14 +234,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @returns false: element does not exist
          *           true: element exists
          */
-        private bool ForEach (int number)
+        private bool ForEach(int number)
         {
             /*
              * If we don't have any array, we can't have ever done
              * any calls here before, so allocate an array big enough
              * and set everything else to the beginning.
              */
-            if (array == null) {
+            if(array == null)
+            {
                 array = new KeyValuePair<object, object>[dnary.Count];
                 arrayValid = 0;
             }
@@ -233,17 +250,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             /*
              * If dictionary modified since last enumeration, get a new enumerator.
              */
-            if (arrayValid == 0) {
-                enumr = dnary.GetEnumerator ();
+            if(arrayValid == 0)
+            {
+                enumr = dnary.GetEnumerator();
                 enumrValid = true;
             }
 
             /*
              * Make sure we have filled the array up enough for requested element.
              */
-            while ((arrayValid <= number) && enumrValid && enumr.MoveNext ()) {
-                if (arrayValid >= array.Length) {
-                    Array.Resize<KeyValuePair<object, object>> (ref array, dnary.Count);
+            while((arrayValid <= number) && enumrValid && enumr.MoveNext())
+            {
+                if(arrayValid >= array.Length)
+                {
+                    Array.Resize<KeyValuePair<object, object>>(ref array, dnary.Count);
                 }
                 array[arrayValid++] = enumr.Current;
             }
@@ -258,17 +278,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @brief Transmit array out in such a way that it can be reconstructed,
          *        including any in-progress ForEach() enumerations.
          */
-        public delegate void SendArrayObjDelegate (object graph);
-        public void SendArrayObj (SendArrayObjDelegate sendObj)
+        public delegate void SendArrayObjDelegate(object graph);
+        public void SendArrayObj(SendArrayObjDelegate sendObj)
         {
             /*
              * Set the count then the elements themselves.
              * UnfixKey() because sendObj doesn't handle XMRArrayListKeys.
              */
-            sendObj (dnary.Count);
-            foreach (KeyValuePair<object, object> kvp in dnary) {
-                sendObj (UnfixKey (kvp.Key));
-                sendObj (kvp.Value);
+            sendObj(dnary.Count);
+            foreach(KeyValuePair<object, object> kvp in dnary)
+            {
+                sendObj(UnfixKey(kvp.Key));
+                sendObj(kvp.Value);
             }
         }
 
@@ -278,10 +299,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *        at the exact spot and in the exact same order as they
          *        were in on the sending side.
          */
-        public delegate object RecvArrayObjDelegate ();
-        public void RecvArrayObj (RecvArrayObjDelegate recvObj)
+        public delegate object RecvArrayObjDelegate();
+        public void RecvArrayObj(RecvArrayObjDelegate recvObj)
         {
-            heapUse = inst.UpdateHeapUse (heapUse, EMPTYHEAP);
+            heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP);
 
             /*
              * Cause any enumeration to refill the array from the sorted dictionary.
@@ -294,14 +315,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             /*
              * Fill dictionary.
              */
-            dnary.Clear ();
-            int count = (int)recvObj ();
-            while (-- count >= 0) {
-                object key = FixKey (recvObj ());
-                object val = recvObj ();
-                int htuse = HeapTrackerObject.Size (key) + HeapTrackerObject.Size (val);
-                heapUse = inst.UpdateHeapUse (heapUse, heapUse + htuse);
-                dnary.Add (key, val);
+            dnary.Clear();
+            int count = (int)recvObj();
+            while(--count >= 0)
+            {
+                object key = FixKey(recvObj());
+                object val = recvObj();
+                int htuse = HeapTrackerObject.Size(key) + HeapTrackerObject.Size(val);
+                heapUse = inst.UpdateHeapUse(heapUse, heapUse + htuse);
+                dnary.Add(key, val);
             }
         }
 
@@ -310,16 +332,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * So strip off any LSL-ness from the types.
          * We also deep-strip any given lists used as keys (multi-dimensional arrays).
          */
-        public static object FixKey (object key)
-        {
-            if (key is LSL_Integer) return (int)(LSL_Integer)key;
-            if (key is LSL_Float)   return (double)(LSL_Float)key;
-            if (key is LSL_Key)     return (string)(LSL_Key)key;
-            if (key is LSL_String)  return (string)(LSL_String)key;
-            if (key is LSL_List) {
+        public static object FixKey(object key)
+        {
+            if(key is LSL_Integer)
+                return (int)(LSL_Integer)key;
+            if(key is LSL_Float)
+                return (double)(LSL_Float)key;
+            if(key is LSL_Key)
+                return (string)(LSL_Key)key;
+            if(key is LSL_String)
+                return (string)(LSL_String)key;
+            if(key is LSL_List)
+            {
                 object[] data = ((LSL_List)key).Data;
-                if (data.Length == 1) return FixKey (data[0]);
-                return new XMRArrayListKey ((LSL_List)key);
+                if(data.Length == 1)
+                    return FixKey(data[0]);
+                return new XMRArrayListKey((LSL_List)key);
             }
             return key;  // int, double, string, LSL_Vector, LSL_Rotation, etc are ok as is
         }
@@ -329,99 +357,119 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *        LSL_List, not the sanitized one, as the script compiler expects an LSL_List.
          *        Any other sanitized types can remain as is (int, string, etc).
          */
-        private static object UnfixKey (object key)
+        private static object UnfixKey(object key)
         {
-            if (key is XMRArrayListKey) key = ((XMRArrayListKey)key).GetOriginal ();
+            if(key is XMRArrayListKey)
+                key = ((XMRArrayListKey)key).GetOriginal();
             return key;
         }
     }
 
-    public class XMRArrayKeyComparer : IComparer<object> {
+    public class XMRArrayKeyComparer: IComparer<object>
+    {
 
-        public static XMRArrayKeyComparer singleton = new XMRArrayKeyComparer ();
+        public static XMRArrayKeyComparer singleton = new XMRArrayKeyComparer();
 
         /**
          * @brief Compare two keys
          */
-        public int Compare (object x, object y)  // IComparer<object>
+        public int Compare(object x, object y)  // IComparer<object>
         {
             /*
              * Use short type name (eg, String, Int32, XMRArrayListKey) as most significant part of key.
              */
-            string xtn = x.GetType ().Name;
-            string ytn = y.GetType ().Name;
-            int ctn = String.CompareOrdinal (xtn, ytn);
-            if (ctn != 0) return ctn;
+            string xtn = x.GetType().Name;
+            string ytn = y.GetType().Name;
+            int ctn = String.CompareOrdinal(xtn, ytn);
+            if(ctn != 0)
+                return ctn;
 
             ComparerDelegate cd;
-            if (!comparers.TryGetValue (xtn, out cd)) {
-                throw new Exception ("unsupported key type " + xtn);
+            if(!comparers.TryGetValue(xtn, out cd))
+            {
+                throw new Exception("unsupported key type " + xtn);
             }
-            return cd (x, y);
+            return cd(x, y);
         }
 
-        private delegate int ComparerDelegate (object a, object b);
+        private delegate int ComparerDelegate(object a, object b);
 
-        private static Dictionary<string, ComparerDelegate> comparers = BuildComparers ();
+        private static Dictionary<string, ComparerDelegate> comparers = BuildComparers();
 
-        private static Dictionary<string, ComparerDelegate> BuildComparers ()
+        private static Dictionary<string, ComparerDelegate> BuildComparers()
         {
-            Dictionary<string, ComparerDelegate> cmps = new Dictionary<string, ComparerDelegate> ();
-            cmps.Add (typeof (double).Name,     MyFloatComparer);
-            cmps.Add (typeof (int).Name,             MyIntComparer);
-            cmps.Add (typeof (XMRArrayListKey).Name, MyListKeyComparer);
-            cmps.Add (typeof (LSL_Rotation).Name,    MyRotationComparer);
-            cmps.Add (typeof (string).Name,          MyStringComparer);
-            cmps.Add (typeof (LSL_Vector).Name,      MyVectorComparer);
+            Dictionary<string, ComparerDelegate> cmps = new Dictionary<string, ComparerDelegate>();
+            cmps.Add(typeof(double).Name, MyFloatComparer);
+            cmps.Add(typeof(int).Name, MyIntComparer);
+            cmps.Add(typeof(XMRArrayListKey).Name, MyListKeyComparer);
+            cmps.Add(typeof(LSL_Rotation).Name, MyRotationComparer);
+            cmps.Add(typeof(string).Name, MyStringComparer);
+            cmps.Add(typeof(LSL_Vector).Name, MyVectorComparer);
             return cmps;
         }
 
-        private static int MyFloatComparer (object a, object b)
+        private static int MyFloatComparer(object a, object b)
         {
             double af = (double)a;
             double bf = (double)b;
-            if (af < bf) return -1;
-            if (af > bf) return  1;
+            if(af < bf)
+                return -1;
+            if(af > bf)
+                return 1;
             return 0;
         }
-        private static int MyIntComparer (object a, object b)
+        private static int MyIntComparer(object a, object b)
         {
             return (int)a - (int)b;
         }
-        private static int MyListKeyComparer (object a, object b)
+        private static int MyListKeyComparer(object a, object b)
         {
             XMRArrayListKey alk = (XMRArrayListKey)a;
             XMRArrayListKey blk = (XMRArrayListKey)b;
-            return XMRArrayListKey.Compare (alk, blk);
+            return XMRArrayListKey.Compare(alk, blk);
         }
-        private static int MyRotationComparer (object a, object b)
+        private static int MyRotationComparer(object a, object b)
         {
             LSL_Rotation ar = (LSL_Rotation)a;
             LSL_Rotation br = (LSL_Rotation)b;
-            if (ar.x < br.x) return -1;
-            if (ar.x > br.x) return  1;
-            if (ar.y < br.y) return -1;
-            if (ar.y > br.y) return  1;
-            if (ar.z < br.z) return -1;
-            if (ar.z > br.z) return  1;
-            if (ar.s < br.s) return -1;
-            if (ar.s > br.s) return  1;
+            if(ar.x < br.x)
+                return -1;
+            if(ar.x > br.x)
+                return 1;
+            if(ar.y < br.y)
+                return -1;
+            if(ar.y > br.y)
+                return 1;
+            if(ar.z < br.z)
+                return -1;
+            if(ar.z > br.z)
+                return 1;
+            if(ar.s < br.s)
+                return -1;
+            if(ar.s > br.s)
+                return 1;
             return 0;
         }
-        private static int MyStringComparer (object a, object b)
+        private static int MyStringComparer(object a, object b)
         {
-            return String.CompareOrdinal ((string)a, (string)b);
+            return String.CompareOrdinal((string)a, (string)b);
         }
-        private static int MyVectorComparer (object a, object b)
+        private static int MyVectorComparer(object a, object b)
         {
             LSL_Vector av = (LSL_Vector)a;
             LSL_Vector bv = (LSL_Vector)b;
-            if (av.x < bv.x) return -1;
-            if (av.x > bv.x) return  1;
-            if (av.y < bv.y) return -1;
-            if (av.y > bv.y) return  1;
-            if (av.z < bv.z) return -1;
-            if (av.z > bv.z) return  1;
+            if(av.x < bv.x)
+                return -1;
+            if(av.x > bv.x)
+                return 1;
+            if(av.y < bv.y)
+                return -1;
+            if(av.y > bv.y)
+                return 1;
+            if(av.z < bv.z)
+                return -1;
+            if(av.z > bv.z)
+                return 1;
             return 0;
         }
     }
@@ -433,7 +481,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
      *        Note that just like LSL_Lists, we consider these objects to be immutable, so they can be directly used as keys in
      *        the dictionary as they don't ever change.
      */
-    public class XMRArrayListKey {
+    public class XMRArrayListKey
+    {
         private LSL_List original;
         private object[] cleaned;
         private int length;
@@ -443,18 +492,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @brief Construct a sanitized object[] from a list.
          *        Also save the original list in case we need it later.
          */
-        public XMRArrayListKey (LSL_List key)
+        public XMRArrayListKey(LSL_List key)
         {
             original = key;
             object[] given = key.Data;
-            int len  = given.Length;
-            length   = len;
-            cleaned  = new object[len];
-            int hc   = len;
-            for (int i = 0; i < len; i ++) {
-                object v   = XMR_Array.FixKey (given[i]);
-                hc        += hc + ((hc < 0) ? 1 : 0);
-                hc        ^= v.GetHashCode ();
+            int len = given.Length;
+            length = len;
+            cleaned = new object[len];
+            int hc = len;
+            for(int i = 0; i < len; i++)
+            {
+                object v = XMR_Array.FixKey(given[i]);
+                hc += hc + ((hc < 0) ? 1 : 0);
+                hc ^= v.GetHashCode();
                 cleaned[i] = v;
             }
             hashCode = hc;
@@ -463,8 +513,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Get heap tracking size.
          */
-        public int Size {
-            get {
+        public int Size
+        {
+            get
+            {
                 return original.Size;
             }
         }
@@ -472,15 +524,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief See if the given object is an XMRArrayListKey and every value is equal to our own.
          */
-        public override bool Equals (object o)
+        public override bool Equals(object o)
         {
-            if (!(o is XMRArrayListKey)) return false;
+            if(!(o is XMRArrayListKey))
+                return false;
             XMRArrayListKey a = (XMRArrayListKey)o;
             int len = a.length;
-            if (len != length) return false;
-            if (a.hashCode != hashCode) return false;
-            for (int i = 0; i < len; i ++) {
-                if (!cleaned[i].Equals (a.cleaned[i])) return false;
+            if(len != length)
+                return false;
+            if(a.hashCode != hashCode)
+                return false;
+            for(int i = 0; i < len; i++)
+            {
+                if(!cleaned[i].Equals(a.cleaned[i]))
+                    return false;
             }
             return true;
         }
@@ -488,7 +545,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Get an hash code.
          */
-        public override int GetHashCode ()
+        public override int GetHashCode()
         {
             return hashCode;
         }
@@ -496,15 +553,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Compare for key sorting.
          */
-        public static int Compare (XMRArrayListKey x, XMRArrayListKey y)
+        public static int Compare(XMRArrayListKey x, XMRArrayListKey y)
         {
             int j = x.length - y.length;
-            if (j == 0) {
-                for (int i = 0; i < x.length; i ++) {
+            if(j == 0)
+            {
+                for(int i = 0; i < x.length; i++)
+                {
                     object xo = x.cleaned[i];
                     object yo = y.cleaned[i];
-                    j = XMRArrayKeyComparer.singleton.Compare (xo, yo);
-                    if (j != 0) break;
+                    j = XMRArrayKeyComparer.singleton.Compare(xo, yo);
+                    if(j != 0)
+                        break;
                 }
             }
             return j;
@@ -513,7 +573,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Get the original LSL_List we were built from.
          */
-        public LSL_List GetOriginal ()
+        public LSL_List GetOriginal()
         {
             return original;
         }
@@ -521,14 +581,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Debugging
          */
-        public override string ToString ()
-        {
-            StringBuilder sb = new StringBuilder ();
-            for (int i = 0; i < length; i ++) {
-                if (i > 0) sb.Append (',');
-                sb.Append (cleaned[i].ToString ());
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i < length; i++)
+            {
+                if(i > 0)
+                    sb.Append(',');
+                sb.Append(cleaned[i].ToString());
             }
-            return sb.ToString ();
+            return sb.ToString();
         }
     }
 }

+ 578 - 0
OpenSim/Region/ScriptEngine/YEngine/XMREngXmrTestLs.cs

@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using log4net;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public partial class Yengine
+    {
+
+        private void XmrTestLs(string[] args, int indx)
+        {
+            bool flagFull = false;
+            bool flagQueues = false;
+            bool flagTopCPU = false;
+            int maxScripts = 0x7FFFFFFF;
+            int numScripts = 0;
+            string outName = null;
+            XMRInstance[] instances;
+
+            /*
+             * Decode command line options.
+             */
+            for(int i = indx; i < args.Length; i++)
+            {
+                if(args[i] == "-full")
+                {
+                    flagFull = true;
+                    continue;
+                }
+                if(args[i] == "-help")
+                {
+                    m_log.Info("[YEngine]: xmr ls -full -max=<number> -out=<filename> -queues -topcpu");
+                    return;
+                }
+                if(args[i].StartsWith("-max="))
+                {
+                    try
+                    {
+                        maxScripts = Convert.ToInt32(args[i].Substring(5));
+                    }
+                    catch(Exception e)
+                    {
+                        m_log.Error("[YEngine]: bad max " + args[i].Substring(5) + ": " + e.Message);
+                        return;
+                    }
+                    continue;
+                }
+                if(args[i].StartsWith("-out="))
+                {
+                    outName = args[i].Substring(5);
+                    continue;
+                }
+                if(args[i] == "-queues")
+                {
+                    flagQueues = true;
+                    continue;
+                }
+                if(args[i] == "-topcpu")
+                {
+                    flagTopCPU = true;
+                    continue;
+                }
+                if(args[i][0] == '-')
+                {
+                    m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'xmr ls -help'");
+                    return;
+                }
+            }
+
+            TextWriter outFile = null;
+            if(outName != null)
+            {
+                try
+                {
+                    outFile = File.CreateText(outName);
+                }
+                catch(Exception e)
+                {
+                    m_log.Error("[YEngine]: error creating " + outName + ": " + e.Message);
+                    return;
+                }
+            }
+            else
+            {
+                outFile = new LogInfoTextWriter(m_log);
+            }
+
+            try
+            {
+
+                /*
+                 * Scan instance list to find those that match selection criteria.
+                 */
+                if(!Monitor.TryEnter(m_InstancesDict, 100))
+                {
+                    m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
+                    return;
+                }
+                try
+                {
+                    instances = new XMRInstance[m_InstancesDict.Count];
+                    foreach(XMRInstance ins in m_InstancesDict.Values)
+                    {
+                        if(InstanceMatchesArgs(ins, args, indx))
+                        {
+                            instances[numScripts++] = ins;
+                        }
+                    }
+                }
+                finally
+                {
+                    Monitor.Exit(m_InstancesDict);
+                }
+
+                /*
+                 * Maybe sort by descending CPU time.
+                 */
+                if(flagTopCPU)
+                {
+                    Array.Sort<XMRInstance>(instances, CompareInstancesByCPUTime);
+                }
+
+                /*
+                 * Print the entries.
+                 */
+                if(!flagFull)
+                {
+                    outFile.WriteLine("                              ItemID" +
+                                      "   CPU(ms)" +
+                                      " NumEvents" +
+                                      " Status    " +
+                                      " World Position                  " +
+                                      " <Part>:<Item>");
+                }
+                for(int i = 0; (i < numScripts) && (i < maxScripts); i++)
+                {
+                    outFile.WriteLine(instances[i].RunTestLs(flagFull));
+                }
+
+                /*
+                 * Print number of scripts that match selection criteria,
+                 * even if we were told to print fewer.
+                 */
+                outFile.WriteLine("total of {0} script(s)", numScripts);
+
+                /*
+                 * If -queues given, print out queue contents too.
+                 */
+                if(flagQueues)
+                {
+                    LsQueue(outFile, "start", m_StartQueue, args, indx);
+                    LsQueue(outFile, "sleep", m_SleepQueue, args, indx);
+                    LsQueue(outFile, "yield", m_YieldQueue, args, indx);
+                }
+            }
+            finally
+            {
+                outFile.Close();
+            }
+        }
+
+        private void XmrTestPev(string[] args, int indx)
+        {
+            bool flagAll = false;
+            int numScripts = 0;
+            XMRInstance[] instances;
+
+            /*
+             * Decode command line options.
+             */
+            int i, j;
+            List<string> selargs = new List<string>(args.Length);
+            MethodInfo[] eventmethods = typeof(IEventHandlers).GetMethods();
+            MethodInfo eventmethod;
+            for(i = indx; i < args.Length; i++)
+            {
+                string arg = args[i];
+                if(arg == "-all")
+                {
+                    flagAll = true;
+                    continue;
+                }
+                if(arg == "-help")
+                {
+                    m_log.Info("[YEngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
+                    return;
+                }
+                if(arg[0] == '-')
+                {
+                    m_log.Error("[YEngine]: unknown option " + arg + ", try 'xmr pev -help'");
+                    return;
+                }
+                for(j = 0; j < eventmethods.Length; j++)
+                {
+                    eventmethod = eventmethods[j];
+                    if(eventmethod.Name == arg)
+                        goto gotevent;
+                }
+                selargs.Add(arg);
+            }
+            m_log.Error("[YEngine]: missing <event-name> <params...>, try 'xmr pev -help'");
+            return;
+            gotevent:
+            string eventname = eventmethod.Name;
+            StringBuilder sourcesb = new StringBuilder();
+            while(++i < args.Length)
+            {
+                sourcesb.Append(' ');
+                sourcesb.Append(args[i]);
+            }
+            string sourcest = sourcesb.ToString();
+            string sourcehash;
+            youveanerror = false;
+            Token t = TokenBegin.Construct("", null, ErrorMsg, sourcest, out sourcehash);
+            if(youveanerror)
+                return;
+            ParameterInfo[] paraminfos = eventmethod.GetParameters();
+            object[] paramvalues = new object[paraminfos.Length];
+            i = 0;
+            while(!((t = t.nextToken) is TokenEnd))
+            {
+                if(i >= paramvalues.Length)
+                {
+                    ErrorMsg(t, "extra parameter(s)");
+                    return;
+                }
+                paramvalues[i] = ParseParamValue(ref t);
+                if(paramvalues[i] == null)
+                    return;
+                i++;
+            }
+            OpenSim.Region.ScriptEngine.Shared.EventParams eps =
+                    new OpenSim.Region.ScriptEngine.Shared.EventParams(eventname, paramvalues, zeroDetectParams);
+
+            /*
+             * Scan instance list to find those that match selection criteria.
+             */
+            if(!Monitor.TryEnter(m_InstancesDict, 100))
+            {
+                m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
+                return;
+            }
+
+            try
+            {
+                instances = new XMRInstance[m_InstancesDict.Count];
+                foreach(XMRInstance ins in m_InstancesDict.Values)
+                {
+                    if(flagAll || InstanceMatchesArgs(ins, selargs.ToArray(), 0))
+                    {
+                        instances[numScripts++] = ins;
+                    }
+                }
+            }
+            finally
+            {
+                Monitor.Exit(m_InstancesDict);
+            }
+
+            /*
+             * Post event to the matching instances.
+             */
+            for(i = 0; i < numScripts; i++)
+            {
+                XMRInstance inst = instances[i];
+                m_log.Info("[YEngine]: post " + eventname + " to " + inst.m_DescName);
+                inst.PostEvent(eps);
+            }
+        }
+
+        private object ParseParamValue(ref Token token)
+        {
+            if(token is TokenFloat)
+            {
+                return new LSL_Float(((TokenFloat)token).val);
+            }
+            if(token is TokenInt)
+            {
+                return new LSL_Integer(((TokenInt)token).val);
+            }
+            if(token is TokenStr)
+            {
+                return new LSL_String(((TokenStr)token).val);
+            }
+            if(token is TokenKwCmpLT)
+            {
+                List<double> valuelist = new List<double>();
+                while(!((token = token.nextToken) is TokenKwCmpGT))
+                {
+                    if(!(token is TokenKwComma))
+                    {
+                        object value = ParseParamValue(ref token);
+                        if(value == null)
+                            return null;
+                        if(value is int)
+                            value = (double)(int)value;
+                        if(!(value is double))
+                        {
+                            ErrorMsg(token, "must be float or integer constant");
+                            return null;
+                        }
+                        valuelist.Add((double)value);
+                    }
+                    else if(token.prevToken is TokenKwComma)
+                    {
+                        ErrorMsg(token, "missing constant");
+                        return null;
+                    }
+                }
+                double[] values = valuelist.ToArray();
+                switch(values.Length)
+                {
+                    case 3:
+                        {
+                            return new LSL_Vector(values[0], values[1], values[2]);
+                        }
+                    case 4:
+                        {
+                            return new LSL_Rotation(values[0], values[1], values[2], values[3]);
+                        }
+                    default:
+                        {
+                            ErrorMsg(token, "not rotation or vector");
+                            return null;
+                        }
+                }
+            }
+            if(token is TokenKwBrkOpen)
+            {
+                List<object> valuelist = new List<object>();
+                while(!((token = token.nextToken) is TokenKwBrkClose))
+                {
+                    if(!(token is TokenKwComma))
+                    {
+                        object value = ParseParamValue(ref token);
+                        if(value == null)
+                            return null;
+                        valuelist.Add(value);
+                    }
+                    else if(token.prevToken is TokenKwComma)
+                    {
+                        ErrorMsg(token, "missing constant");
+                        return null;
+                    }
+                }
+                return new LSL_List(valuelist.ToArray());
+            }
+            if(token is TokenName)
+            {
+                FieldInfo field = typeof(OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass).GetField(((TokenName)token).val);
+                if((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly)))
+                {
+                    return field.GetValue(null);
+                }
+            }
+            ErrorMsg(token, "invalid constant");
+            return null;
+        }
+
+        private bool youveanerror;
+        private void ErrorMsg(Token token, string message)
+        {
+            youveanerror = true;
+            m_log.Info("[YEngine]: " + token.posn + " " + message);
+        }
+
+        private void XmrTestReset(string[] args, int indx)
+        {
+            bool flagAll = false;
+            int numScripts = 0;
+            XMRInstance[] instances;
+
+            if(args.Length <= indx)
+            {
+                m_log.Error("[YEngine]: must specify part of script name or -all for all scripts");
+                return;
+            }
+
+            /*
+             * Decode command line options.
+             */
+            for(int i = indx; i < args.Length; i++)
+            {
+                if(args[i] == "-all")
+                {
+                    flagAll = true;
+                    continue;
+                }
+                if(args[i] == "-help")
+                {
+                    m_log.Info("[YEngine]: xmr reset -all | <part-of-script-name>");
+                    return;
+                }
+                if(args[i][0] == '-')
+                {
+                    m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'xmr reset -help'");
+                    return;
+                }
+            }
+
+            /*
+             * Scan instance list to find those that match selection criteria.
+             */
+            if(!Monitor.TryEnter(m_InstancesDict, 100))
+            {
+                m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
+                return;
+            }
+
+            try
+            {
+                instances = new XMRInstance[m_InstancesDict.Count];
+                foreach(XMRInstance ins in m_InstancesDict.Values)
+                {
+                    if(flagAll || InstanceMatchesArgs(ins, args, indx))
+                    {
+                        instances[numScripts++] = ins;
+                    }
+                }
+            }
+            finally
+            {
+                Monitor.Exit(m_InstancesDict);
+            }
+
+            /*
+             * Reset the instances as if someone clicked their "Reset" button.
+             */
+            for(int i = 0; i < numScripts; i++)
+            {
+                XMRInstance inst = instances[i];
+                m_log.Info("[YEngine]: resetting " + inst.m_DescName);
+                inst.Reset();
+            }
+        }
+
+        private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b)
+        {
+            if(a == null)
+            {
+                return (b == null) ? 0 : 1;
+            }
+            if(b == null)
+            {
+                return -1;
+            }
+            if(b.m_CPUTime < a.m_CPUTime)
+                return -1;
+            if(b.m_CPUTime > a.m_CPUTime)
+                return 1;
+            return 0;
+        }
+
+        private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx)
+        {
+            outFile.WriteLine("Queue " + name + ":");
+            lock(queue)
+            {
+                for(XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst)
+                {
+                    try
+                    {
+
+                        /*
+                         * Try to print instance name.
+                         */
+                        if(InstanceMatchesArgs(inst, args, indx))
+                        {
+                            outFile.WriteLine("   " + inst.ItemID.ToString() + " " + inst.m_DescName);
+                        }
+                    }
+                    catch(Exception e)
+                    {
+
+                        /*
+                         * Sometimes there are instances in the queue that are disposed.
+                         */
+                        outFile.WriteLine("   " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message);
+                    }
+                }
+            }
+        }
+
+        private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx)
+        {
+            bool hadSomethingToCompare = false;
+
+            for(int i = indx; i < args.Length; i++)
+            {
+                if(args[i][0] != '-')
+                {
+                    hadSomethingToCompare = true;
+                    if(ins.m_DescName.Contains(args[i]))
+                        return true;
+                    if(ins.ItemID.ToString().Contains(args[i]))
+                        return true;
+                    if(ins.AssetID.ToString().Contains(args[i]))
+                        return true;
+                }
+            }
+            return !hadSomethingToCompare;
+        }
+    }
+
+    /**
+     * @brief Make m_log.Info look like a text writer.
+     */
+    public class LogInfoTextWriter: TextWriter
+    {
+        private StringBuilder sb = new StringBuilder();
+        private ILog m_log;
+        public LogInfoTextWriter(ILog m_log)
+        {
+            this.m_log = m_log;
+        }
+        public override void Write(char c)
+        {
+            if(c == '\n')
+            {
+                m_log.Info("[YEngine]: " + sb.ToString());
+                sb.Remove(0, sb.Length);
+            }
+            else
+            {
+                sb.Append(c);
+            }
+        }
+        public override void Close()
+        {
+        }
+        public override Encoding Encoding
+        {
+            get
+            {
+                return Encoding.UTF8;
+            }
+        }
+    }
+}

+ 1901 - 0
OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs

@@ -0,0 +1,1901 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// based on YEngine from Mike Rieker (Dreamnation) and Melanie Thielker
+// but with several changes to be more cross platform.
+
+using log4net;
+using Mono.Addins;
+using Nini.Config;
+using OpenSim.Framework;
+using OpenSim.Framework.Console;
+using OpenSim.Framework.Monitoring;
+using OpenSim.Region.ClientStack.Linden;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.ScriptEngine.Interfaces;
+using OpenSim.Region.ScriptEngine.Shared;
+using OpenSim.Region.ScriptEngine.Shared.Api;
+using OpenMetaverse;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Threading;
+using System.Timers;
+using System.Xml;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+[assembly: Addin("YEngine", OpenSim.VersionInfo.VersionNumber)]
+[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "YEngine")]
+    public partial class Yengine: INonSharedRegionModule, IScriptEngine,
+            IScriptModule
+    {
+        public static readonly DetectParams[] zeroDetectParams = new DetectParams[0];
+        private static ArrayList noScriptErrors = new ArrayList();
+        public static readonly ILog m_log =
+            LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+        private static readonly string[] scriptReferencedAssemblies = new string[0];
+
+        private bool m_LateInit;
+        private bool m_TraceCalls;
+        public bool m_Verbose;
+        public bool m_ScriptDebug;
+        public bool m_ScriptDebugSaveSource;
+        public bool m_ScriptDebugSaveIL;
+        public Scene m_Scene;
+        private IConfigSource m_ConfigSource;
+        private IConfig m_Config;
+        private string m_ScriptBasePath;
+        private bool m_Enabled = false;
+        public bool m_StartProcessing = false;
+        public bool m_UseSourceHashCode = false;
+        private Dictionary<UUID, ArrayList> m_ScriptErrors =
+                new Dictionary<UUID, ArrayList>();
+        private Dictionary<UUID, List<UUID>> m_ObjectItemList =
+                new Dictionary<UUID, List<UUID>>();
+        private Dictionary<UUID, XMRInstance[]> m_ObjectInstArray =
+                new Dictionary<UUID, XMRInstance[]>();
+        public Dictionary<string, FieldInfo> m_XMRInstanceApiCtxFieldInfos =
+                new Dictionary<string, FieldInfo>();
+        public int m_StackSize;
+        private int m_HeapSize;
+        private Thread m_SleepThread = null;
+
+        private bool m_Exiting = false;
+
+        private int m_MaintenanceInterval = 10;
+        private System.Timers.Timer m_MaintenanceTimer;
+        public int numThreadScriptWorkers;
+
+        private object m_FrameUpdateLock = new object();
+        private event ThreadStart m_FrameUpdateList = null;
+
+        // Various instance lists:
+        //   m_InstancesDict = all known instances
+        //                     find an instance given its itemID
+        //   m_StartQueue = instances that have just had event queued to them
+        //   m_YieldQueue = instances that are ready to run right now
+        //   m_SleepQueue = instances that have m_SleepUntil valid
+        //                  sorted by ascending m_SleepUntil
+        private Dictionary<UUID, XMRInstance> m_InstancesDict =
+                new Dictionary<UUID, XMRInstance>();
+        public Queue<ThreadStart> m_ThunkQueue = new Queue<ThreadStart>();
+        public XMRInstQueue m_StartQueue = new XMRInstQueue();
+        public XMRInstQueue m_YieldQueue = new XMRInstQueue();
+        public XMRInstQueue m_SleepQueue = new XMRInstQueue();
+        private string m_LockedDict = "nobody";
+
+        public Yengine()
+        {
+        }
+
+        public string Name
+        {
+            get
+            {
+                return "YEngine";
+            }
+        }
+
+        public Type ReplaceableInterface
+        {
+            get
+            {
+                return null;
+            }
+        }
+
+        public string ScriptEnginePath
+        {
+            get
+            {
+                return m_ScriptBasePath;
+            }
+        }
+
+        public string ScriptClassName
+        {
+            get
+            {
+                return "YEngineScript";
+            }
+        }
+
+        public string ScriptBaseClassName
+        {
+            get
+            {
+                return typeof(XMRInstance).FullName;
+            }
+        }
+
+        public ParameterInfo[] ScriptBaseClassParameters
+        {
+            get
+            {
+                return typeof(XMRInstance).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters();
+            }
+        }
+
+        public string[] ScriptReferencedAssemblies
+        {
+            get
+            {
+                return scriptReferencedAssemblies;
+            }
+        }
+
+        public void Initialise(IConfigSource config)
+        {
+            TraceCalls("[YEngine]: Initialize entry");
+            m_ConfigSource = config;
+
+            ////foreach (IConfig icfg in config.Configs) {
+            ////    m_log.Debug("[YEngine]: Initialise: configs[" + icfg.Name + "]");
+            ////    foreach (string key in icfg.GetKeys ()) {
+            ////        m_log.Debug("[YEngine]: Initialise:     " + key + "=" + icfg.GetExpanded (key));
+            ////    }
+            ////}
+
+            m_Enabled = false;
+            m_Config = config.Configs["YEngine"];
+            if(m_Config == null)
+            {
+                m_log.Info("[YEngine]: no config, assuming disabled");
+                return;
+            }
+            m_Enabled = m_Config.GetBoolean("Enabled", false);
+            m_log.InfoFormat("[YEngine]: config enabled={0}", m_Enabled);
+            if(!m_Enabled)
+                return;
+
+            m_UseSourceHashCode = m_Config.GetBoolean("UseSourceHashCode", false);
+            numThreadScriptWorkers = m_Config.GetInt("NumThreadScriptWorkers", 1);
+
+            m_TraceCalls = m_Config.GetBoolean("TraceCalls", false);
+            m_Verbose = m_Config.GetBoolean("Verbose", false);
+            m_ScriptDebug = m_Config.GetBoolean("ScriptDebug", false);
+            m_ScriptDebugSaveSource = m_Config.GetBoolean("ScriptDebugSaveSource", false);
+            m_ScriptDebugSaveIL = m_Config.GetBoolean("ScriptDebugSaveIL", false);
+
+            m_StackSize = m_Config.GetInt("ScriptStackSize", 2048) << 10;
+            m_HeapSize = m_Config.GetInt("ScriptHeapSize", 1024) << 10;
+
+            // Verify that our ScriptEventCode's match OpenSim's scriptEvent's.
+            bool err = false;
+            for(int i = 0; i < 32; i++)
+            {
+                string mycode = "undefined";
+                string oscode = "undefined";
+                try
+                {
+                    mycode = ((ScriptEventCode)i).ToString();
+                    Convert.ToInt32(mycode);
+                    mycode = "undefined";
+                }
+                catch { }
+                try
+                {
+                    oscode = ((OpenSim.Region.Framework.Scenes.scriptEvents)(1 << i)).ToString();
+                    Convert.ToInt32(oscode);
+                    oscode = "undefined";
+                }
+                catch { }
+                if(mycode != oscode)
+                {
+                    m_log.ErrorFormat("[YEngine]: {0} mycode={1}, oscode={2}", i, mycode, oscode);
+                    err = true;
+                }
+            }
+            if(err)
+            {
+                m_Enabled = false;
+                return;
+            }
+
+            m_SleepThread = StartMyThread(RunSleepThread, "Yengine sleep", ThreadPriority.Normal);
+            for(int i = 0; i < numThreadScriptWorkers; i++)
+                StartThreadWorker(i);
+
+            m_log.InfoFormat("[YEngine]: Enabled, {0}.{1} Meg (0x{2}) stacks",
+                    (m_StackSize >> 20).ToString(),
+                    (((m_StackSize % 0x100000) * 1000)
+                            >> 20).ToString("D3"),
+                    m_StackSize.ToString("X"));
+
+            m_log.InfoFormat("[YEngine]:  ... {0}.{1} Meg (0x{2}) heaps",
+                    (m_HeapSize >> 20).ToString(),
+                    (((m_HeapSize % 0x100000) * 1000)
+                            >> 20).ToString("D3"),
+                    m_HeapSize.ToString("X"));
+
+            m_MaintenanceInterval = m_Config.GetInt("MaintenanceInterval", 10);
+
+            if(m_MaintenanceInterval > 0)
+            {
+                m_MaintenanceTimer = new System.Timers.Timer(m_MaintenanceInterval * 60000);
+                m_MaintenanceTimer.Elapsed += DoMaintenance;
+                m_MaintenanceTimer.Start();
+            }
+
+            MainConsole.Instance.Commands.AddCommand("yeng", false,
+                    "yeng",
+                    "yeng [...|help|...] ...",
+                    "Run Yengine script engine commands",
+                    RunTest);
+
+            TraceCalls("[YEngine]: Initialize successful");
+        }
+
+        public void AddRegion(Scene scene)
+        {
+            if(!m_Enabled)
+                return;
+
+            TraceCalls("[YEngine]: YEngine.AddRegion({0})", scene.RegionInfo.RegionName);
+
+            m_Scene = scene;
+
+            m_Scene.RegisterModuleInterface<IScriptModule>(this);
+
+            m_ScriptBasePath = m_Config.GetString("ScriptBasePath", "ScriptEngines");
+            m_ScriptBasePath = Path.Combine(m_ScriptBasePath, "Yengine");
+            m_ScriptBasePath = Path.Combine(m_ScriptBasePath, scene.RegionInfo.RegionID.ToString());
+
+            Directory.CreateDirectory(m_ScriptBasePath);
+
+            m_Scene.EventManager.OnRezScript += OnRezScript;
+
+            m_Scene.StackModuleInterface<IScriptModule>(this);
+        }
+
+        private void OneTimeLateInitialization()
+        {
+            // Build list of defined APIs and their 'this' types and define a field in XMRInstanceSuperType.
+            ApiManager am = new ApiManager();
+            Dictionary<string, Type> apiCtxTypes = new Dictionary<string, Type>();
+            foreach(string api in am.GetApis())
+            {
+                m_log.Debug("[YEngine]: adding api " + api);
+                IScriptApi scriptApi = am.CreateApi(api);
+                Type apiCtxType = scriptApi.GetType();
+                if(api == "LSL")
+                    apiCtxType = typeof(XMRLSL_Api);
+                apiCtxTypes[api] = apiCtxType;
+            }
+
+            if(ScriptCodeGen.xmrInstSuperType == null) // Only create type once!
+            {
+                // Start creating type XMRInstanceSuperType that contains a field
+                // m_ApiManager_<APINAME> that points to the per-instance context
+                // struct for that API, ie, the 'this' value passed to all methods
+                // in that API.  It is in essence:
+
+                //  public class XMRInstanceSuperType : XMRInstance {
+                //      public XMRLSL_Api m_ApiManager_LSL;   // 'this' value for all ll...() functions
+                //      public MOD_Api    m_ApiManager_MOD;   // 'this' value for all mod...() functions
+                //      public OSSL_Api   m_ApiManager_OSSL;  // 'this' value for all os...() functions
+                //              ....
+                //  }
+                AssemblyName assemblyName = new AssemblyName();
+                assemblyName.Name = "XMRInstanceSuperAssembly";
+                AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+                ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("XMRInstanceSuperModule");
+                TypeBuilder typeBuilder = moduleBuilder.DefineType("XMRInstanceSuperType", TypeAttributes.Public | TypeAttributes.Class);
+                typeBuilder.SetParent(typeof(XMRInstance));
+
+                foreach(string apiname in apiCtxTypes.Keys)
+                {
+                    string fieldName = "m_ApiManager_" + apiname;
+                    typeBuilder.DefineField(fieldName, apiCtxTypes[apiname], FieldAttributes.Public);
+                }
+
+                // Finalize definition of XMRInstanceSuperType.
+                // Give the compiler a short name to reference it by,
+                // otherwise it will try to use the AssemblyQualifiedName
+                // and fail miserably.
+                ScriptCodeGen.xmrInstSuperType = typeBuilder.CreateType();
+                ScriptObjWriter.DefineInternalType("xmrsuper", ScriptCodeGen.xmrInstSuperType);
+            }
+
+            // Tell the compiler about all the constants and methods for each API.
+            // We also tell the compiler how to get the per-instance context for each API
+            // by reading the corresponding m_ApiManager_<APINAME> field of XMRInstanceSuperType.
+            foreach(KeyValuePair<string, Type> kvp in apiCtxTypes)
+            {
+                // get API name and the corresponding per-instance context type
+                string api = kvp.Key;
+                Type apiCtxType = kvp.Value;
+
+                // give script compiler an abbreviated name for the API context type
+                ScriptObjWriter.DefineInternalType("apimanager_" + api, apiCtxType);
+
+                // this field tells the compiled code where the per-instance API context object is
+                // eg, for the OSSL API, it is in ((XMRInstanceSuperType)inst).m_ApiManager_OSSL
+                string fieldName = "m_ApiManager_" + api;
+                FieldInfo fieldInfo = ScriptCodeGen.xmrInstSuperType.GetField(fieldName);
+                m_XMRInstanceApiCtxFieldInfos[api] = fieldInfo;
+
+                // now tell the compiler about the constants and methods for the API
+                ScriptConst.AddInterfaceConstants(null, apiCtxType.GetFields());
+                TokenDeclInline.AddInterfaceMethods(null, apiCtxType.GetMethods(), fieldInfo);
+            }
+
+            // Add sim-specific APIs to the compiler.
+            IScriptModuleComms comms = m_Scene.RequestModuleInterface<IScriptModuleComms>();
+            if(comms != null)
+            {
+                // Add methods to list of built-in functions.
+                Delegate[] methods = comms.GetScriptInvocationList();
+                foreach(Delegate m in methods)
+                {
+                    MethodInfo mi = m.Method;
+                    try
+                    {
+                        CommsCallCodeGen cccg = new CommsCallCodeGen(mi, comms, m_XMRInstanceApiCtxFieldInfos["MOD"]);
+                        Verbose("[YEngine]: added comms function " + cccg.fullName);
+                    }
+                    catch(Exception e)
+                    {
+                        m_log.Error("[YEngine]: failed to add comms function " + mi.Name);
+                        m_log.Error("[YEngine]: - " + e.ToString());
+                    }
+                }
+
+                // Add constants to list of built-in constants.
+                Dictionary<string, object> consts = comms.GetConstants();
+                foreach(KeyValuePair<string, object> kvp in consts)
+                {
+                    try
+                    {
+                        ScriptConst sc = ScriptConst.AddConstant(kvp.Key, kvp.Value);
+                        Verbose("[YEngine]: added comms constant " + sc.name);
+                    }
+                    catch(Exception e)
+                    {
+                        m_log.Error("[YEngine]: failed to add comms constant " + kvp.Key);
+                        m_log.Error("[YEngine]: - " + e.Message);
+                    }
+                }
+            }
+            else
+            {
+                Verbose("[YEngine]: comms not enabled");
+            }
+        }
+
+        /**
+         * @brief Generate code for the calls to the comms functions.
+         *        It is a tRUlY EvIL interface.
+         *        To call the function we must call an XMRInstanceSuperType.m_ApiManager_MOD.modInvoker?()
+         *        method passing it the name of the function as a string and the script
+         *        argument list wrapped up in an object[] array.  The modInvoker?() methods 
+         *        do some sick type conversions (with corresponding mallocs) so we can't 
+         *        call the methods directly.
+         */
+        private class CommsCallCodeGen: TokenDeclInline
+        {
+            private static Type[] modInvokerArgTypes = new Type[] { typeof(string), typeof(object[]) };
+            public static FieldInfo xmrInstModApiCtxField;
+
+            private MethodInfo modInvokerMeth;
+            private string methName;
+
+            /**
+             * @brief Constructor
+             * @param mi = method to make available to scripts
+             *        mi.Name = name that is used by scripts
+             *        mi.GetParameters() = parameter list as defined by module
+             *                             includes the 'UUID host','UUID script' parameters that script does not see
+             *                             allowed types for script-visible parameters are as follows:
+             *                                    Single -> float
+             *                                     Int32 -> integer
+             *                        OpenMetaverse.UUID -> key
+             *                                  Object[] -> list
+             *                  OpenMetaverse.Quaternion -> rotation
+             *                                    String -> string
+             *                     OpenMetaverse.Vector3 -> vector
+             *        mi.ReturnType = return type as defined by module
+             *                        types are same as allowed for parameters
+             * @param comms = comms module the method came from
+             * @param apictxfi = what field in XMRInstanceSuperType the 'this' value is for this method
+             */
+            public CommsCallCodeGen(MethodInfo mi, IScriptModuleComms comms, FieldInfo apictxfi)
+                    : base(null, false, NameArgSig(mi), RetType(mi))
+            {
+                methName = mi.Name;
+                string modInvokerName = comms.LookupModInvocation(methName);
+                if(modInvokerName == null)
+                    throw new Exception("cannot find comms method " + methName);
+                modInvokerMeth = typeof(MOD_Api).GetMethod(modInvokerName, modInvokerArgTypes);
+                xmrInstModApiCtxField = apictxfi;
+            }
+
+            // script-visible name(argtype,...) signature string
+            private static string NameArgSig(MethodInfo mi)
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.Append(mi.Name);
+                sb.Append('(');
+                ParameterInfo[] mps = mi.GetParameters();
+                for(int i = 2; i < mps.Length; i++)
+                {
+                    ParameterInfo pi = mps[i];
+                    if(i > 2)
+                        sb.Append(',');
+                    sb.Append(ParamType(pi.ParameterType));
+                }
+                sb.Append(')');
+                return sb.ToString();
+            }
+
+            // script-visible return type
+            // note that although we support void, the comms stuff does not
+            private static TokenType RetType(MethodInfo mi)
+            {
+                Type rt = mi.ReturnType;
+                if(rt == typeof(float))
+                    return new TokenTypeFloat(null);
+                if(rt == typeof(int))
+                    return new TokenTypeInt(null);
+                if(rt == typeof(object[]))
+                    return new TokenTypeList(null);
+                if(rt == typeof(OpenMetaverse.UUID))
+                    return new TokenTypeKey(null);
+                if(rt == typeof(OpenMetaverse.Quaternion))
+                    return new TokenTypeRot(null);
+                if(rt == typeof(string))
+                    return new TokenTypeStr(null);
+                if(rt == typeof(OpenMetaverse.Vector3))
+                    return new TokenTypeVec(null);
+                if(rt == null || rt == typeof(void))
+                    return new TokenTypeVoid(null);
+                throw new Exception("unsupported return type " + rt.Name);
+            }
+
+            // script-visible parameter type
+            private static string ParamType(Type t)
+            {
+                if(t == typeof(float))
+                    return "float";
+                if(t == typeof(int))
+                    return "integer";
+                if(t == typeof(OpenMetaverse.UUID))
+                    return "key";
+                if(t == typeof(object[]))
+                    return "list";
+                if(t == typeof(OpenMetaverse.Quaternion))
+                    return "rotation";
+                if(t == typeof(string))
+                    return "string";
+                if(t == typeof(OpenMetaverse.Vector3))
+                    return "vector";
+                throw new Exception("unsupported parameter type " + t.Name);
+            }
+
+            /**
+             * @brief Called by the compiler to generate a call to the comms function.
+             * @param scg = which script is being compiled
+             * @param errorAt = where in the source code the call is being made (for error messages)
+             * @param result = a temp location to put the return value in if any
+             * @param args = array of script-visible arguments being passed to the function
+             */
+            public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
+            {
+                // Set up 'this' pointer for modInvoker?() = value from ApiManager.CreateApi("MOD").
+                scg.PushXMRInst();
+                scg.ilGen.Emit(errorAt, OpCodes.Castclass, xmrInstModApiCtxField.DeclaringType);
+                scg.ilGen.Emit(errorAt, OpCodes.Ldfld, xmrInstModApiCtxField);
+
+                // Set up 'fname' argument to modInvoker?() = name of the function to be called.
+                scg.ilGen.Emit(errorAt, OpCodes.Ldstr, methName);
+
+                // Set up 'parms' argument to modInvoker?() = object[] of the script-visible parameters,
+                // in their LSL-wrapped form.  Of course, the modInvoker?() method will malloc yet another 
+                // object[] and type-convert these parameters one-by-one with another round of unwrapping 
+                // and wrapping.
+                // Types allowed in this object[]:
+                //    LSL_Float, LSL_Integer, LSL_Key, LSL_List, LSL_Rotation, LSL_String, LSL_Vector
+                int nargs = args.Length;
+                scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, nargs);
+                scg.ilGen.Emit(errorAt, OpCodes.Newarr, typeof(object));
+
+                for(int i = 0; i < nargs; i++)
+                {
+                    scg.ilGen.Emit(errorAt, OpCodes.Dup);
+                    scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, i);
+
+                    // get location and type of argument
+                    CompValu arg = args[i];
+                    TokenType argtype = arg.type;
+
+                    // if already in a form acceptable to modInvoker?(),
+                    // just push it to the stack and convert to object
+                    // by boxing it if necessary
+
+                    // but if something like a double, int, string, etc
+                    // push to stack converting to the LSL-wrapped type
+                    // then convert to object by boxing if necessary
+
+                    Type boxit = null;
+                    if(argtype is TokenTypeLSLFloat)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_Float);
+                    }
+                    else if(argtype is TokenTypeLSLInt)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_Integer);
+                    }
+                    else if(argtype is TokenTypeLSLKey)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_Key);
+                    }
+                    else if(argtype is TokenTypeList)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_List);
+                    }
+                    else if(argtype is TokenTypeRot)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_Rotation);
+                    }
+                    else if(argtype is TokenTypeLSLString)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_String);
+                    }
+                    else if(argtype is TokenTypeVec)
+                    {
+                        args[i].PushVal(scg, errorAt);
+                        boxit = typeof(LSL_Vector);
+                    }
+                    else if(argtype is TokenTypeFloat)
+                    {
+                        args[i].PushVal(scg, errorAt, new TokenTypeLSLFloat(argtype));
+                        boxit = typeof(LSL_Float);
+                    }
+                    else if(argtype is TokenTypeInt)
+                    {
+                        args[i].PushVal(scg, errorAt, new TokenTypeLSLInt(argtype));
+                        boxit = typeof(LSL_Integer);
+                    }
+                    else if(argtype is TokenTypeKey)
+                    {
+                        args[i].PushVal(scg, errorAt, new TokenTypeLSLKey(argtype));
+                        boxit = typeof(LSL_Key);
+                    }
+                    else if(argtype is TokenTypeStr)
+                    {
+                        args[i].PushVal(scg, errorAt, new TokenTypeLSLString(argtype));
+                        boxit = typeof(LSL_String);
+                    }
+                    else
+                        throw new Exception("unsupported arg type " + argtype.GetType().Name);
+
+                    if(boxit.IsValueType)
+                        scg.ilGen.Emit(errorAt, OpCodes.Box, boxit);
+
+                    // pop the object into the object[]
+                    scg.ilGen.Emit(errorAt, OpCodes.Stelem, typeof(object));
+                }
+
+                // Call the modInvoker?() method.
+                // It leaves an LSL-wrapped type on the stack.
+                if(modInvokerMeth.IsVirtual)
+                    scg.ilGen.Emit(errorAt, OpCodes.Callvirt, modInvokerMeth);
+                else
+                    scg.ilGen.Emit(errorAt, OpCodes.Call, modInvokerMeth);
+
+
+                // The 3rd arg to Pop() is the type on the stack, 
+                // ie, what modInvoker?() actually returns.
+                // The Pop() method will wrap/unwrap as needed.
+                Type retSysType = modInvokerMeth.ReturnType;
+                if(retSysType == null)
+                    retSysType = typeof(void);
+                TokenType retTokType = TokenType.FromSysType(errorAt, retSysType);
+                result.Pop(scg, errorAt, retTokType);
+            }
+        }
+
+        /**
+         * @brief Called late in shutdown procedure,
+         *        after the 'Shutting down..." message.
+         */
+        public void RemoveRegion(Scene scene)
+        {
+            if(!m_Enabled)
+                return;
+
+            TraceCalls("[YEngine]: YEngine.RemoveRegion({0})", scene.RegionInfo.RegionName);
+
+            if(m_MaintenanceTimer != null)
+            {
+                m_MaintenanceTimer.Stop();
+                m_MaintenanceTimer.Dispose();
+            }
+
+            // Write script states out to .state files so it will be
+            // available when the region is restarted.
+            DoMaintenance(null, null);
+
+            // Stop executing script threads and wait for final
+            // one to finish (ie, script gets to CheckRun() call).
+            m_Exiting = true;
+            if(m_SleepThread != null)
+            {
+                lock(m_SleepQueue)
+                    Monitor.PulseAll(m_SleepQueue);
+
+                if(!m_SleepThread.Join(250))
+                    m_SleepThread.Abort();
+                m_SleepThread = null;
+            }
+
+            StopThreadWorkers();
+
+            m_Scene.EventManager.OnFrame -= OnFrame;
+            m_Scene.EventManager.OnRezScript -= OnRezScript;
+            m_Scene.EventManager.OnRemoveScript -= OnRemoveScript;
+            m_Scene.EventManager.OnScriptReset -= OnScriptReset;
+            m_Scene.EventManager.OnStartScript -= OnStartScript;
+            m_Scene.EventManager.OnStopScript -= OnStopScript;
+            m_Scene.EventManager.OnGetScriptRunning -= OnGetScriptRunning;
+            m_Scene.EventManager.OnShutdown -= OnShutdown;
+
+            m_Enabled = false;
+            m_Scene = null;
+        }
+
+        public void RegionLoaded(Scene scene)
+        {
+            if(!m_Enabled)
+                return;
+
+            TraceCalls("[YEngine]: YEngine.RegionLoaded({0})", scene.RegionInfo.RegionName);
+
+            m_Scene.EventManager.OnFrame += OnFrame;
+            m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
+            m_Scene.EventManager.OnScriptReset += OnScriptReset;
+            m_Scene.EventManager.OnStartScript += OnStartScript;
+            m_Scene.EventManager.OnStopScript += OnStopScript;
+            m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
+            m_Scene.EventManager.OnShutdown += OnShutdown;
+
+            InitEvents();
+        }
+
+        public void StartProcessing()
+        {
+            m_log.Debug("[YEngine]: StartProcessing entry");
+            m_StartProcessing = true;
+            ResumeThreads();
+            m_log.Debug("[YEngine]: StartProcessing return");
+            m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, "");
+        }
+
+        public void Close()
+        {
+            TraceCalls("[YEngine]: YEngine.Close()");
+        }
+
+        private void RunTest(string module, string[] args)
+        {
+            if(args.Length < 2)
+            {
+                m_log.Info("[YEngine]: missing command, try 'xmr help'");
+                return;
+            }
+
+            m_log.Info("[YEngine]: " + m_Scene.RegionInfo.RegionName);
+
+            switch(args[1])
+            {
+                case "cvv":
+                    m_log.InfoFormat("[YEngine]: compiled version value = {0}",
+                                    ScriptCodeGen.COMPILED_VERSION_VALUE);
+                    break;
+
+                case "help":
+                case "?":
+                    m_log.Info("[YEngine]: xmr cvv - show compiler version value");
+                    m_log.Info("[YEngine]: xmr ls [-help ...]");
+                    m_log.Info("[YEngine]: xmr mv [<newvalue>] - show migration version value");
+                    m_log.Info("[YEngine]: xmr pev [-help ...] - post event");
+                    m_log.Info("[YEngine]: xmr reset [-help ...]");
+                    m_log.Info("[YEngine]: xmr resume - resume script processing");
+                    m_log.Info("[YEngine]: xmr suspend - suspend script processing");
+                    m_log.Info("[YEngine]: xmr tracecalls [yes | no]");
+                    m_log.Info("[YEngine]: xmr verbose [yes | no]");
+                    break;
+
+                case "ls":
+                    XmrTestLs(args, 2);
+                    break;
+
+                case "mvv":
+                    m_log.InfoFormat("[YEngine]: migration version value = {0}",
+                        XMRInstance.migrationVersion);
+                    break;
+
+                case "pev":
+                    XmrTestPev(args, 2);
+                    break;
+
+                case "reset":
+                    XmrTestReset(args, 2);
+                    break;
+
+                case "resume":
+                    m_log.Info("[YEngine]: resuming scripts");
+                    ResumeThreads();
+                    break;
+
+                case "suspend":
+                    m_log.Info("[YEngine]: suspending scripts");
+                    SuspendThreads();
+                    break;
+
+                case "tracecalls":
+                    if(args.Length > 2)
+                        m_TraceCalls = (args[2][0] & 1) != 0;
+                    m_log.Info("[YEngine]: tracecalls " + (m_TraceCalls ? "yes" : "no"));
+                    break;
+
+                case "verbose":
+                    if(args.Length > 2)
+                        m_Verbose = (args[2][0] & 1) != 0;
+                    m_log.Info("[YEngine]: verbose " + (m_Verbose ? "yes" : "no"));
+                    break;
+
+                default:
+                    m_log.Error("[YEngine]: unknown command " + args[1] + ", try 'xmr help'");
+                    break;
+            }
+        }
+
+        // Not required when not using IScriptInstance
+        //
+        public IScriptWorkItem QueueEventHandler(object parms)
+        {
+            return null;
+        }
+
+        public Scene World
+        {
+            get
+            {
+                return m_Scene;
+            }
+        }
+
+        public IScriptModule ScriptModule
+        {
+            get
+            {
+                return this;
+            }
+        }
+
+        public void SaveAllState()
+        {
+            m_log.Error("[YEngine]: YEngine.SaveAllState() called!!");
+        }
+
+#pragma warning disable 0067
+        public event ScriptRemoved OnScriptRemoved;
+        public event ObjectRemoved OnObjectRemoved;
+#pragma warning restore 0067
+
+        // Events targeted at a specific script
+        // ... like listen() for an llListen() call
+        //
+        public bool PostScriptEvent(UUID itemID, EventParams parms)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+                return false;
+
+            TraceCalls("[YEngine]: YEngine.PostScriptEvent({0},{1})", itemID.ToString(), parms.EventName);
+
+            instance.PostEvent(parms);
+            return true;
+        }
+
+        // Events targeted at all scripts in the given prim.
+        //   localID = which prim
+        //   parms   = event to post
+        //
+        public bool PostObjectEvent(uint localID, EventParams parms)
+        {
+            SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
+
+            if(part == null)
+                return false;
+
+            TraceCalls("[YEngine]: YEngine.PostObjectEvent({0},{1})", localID.ToString(), parms.EventName);
+
+            // In SecondLife, attach events go to all scripts of all prims
+            // in a linked object.  So here we duplicate that functionality,
+            // as all we ever get is a single attach event for the whole
+            // object.
+            if(parms.EventName == "attach")
+            {
+                bool posted = false;
+                foreach(SceneObjectPart primpart in part.ParentGroup.Parts)
+                    posted |= PostPrimEvent(primpart, parms);
+
+                return posted;
+            }
+
+            // Other events go to just the scripts in that prim.
+            return PostPrimEvent(part, parms);
+        }
+
+        private bool PostPrimEvent(SceneObjectPart part, EventParams parms)
+        {
+            UUID partUUID = part.UUID;
+
+            // Get list of script instances running in the object.
+            XMRInstance[] objInstArray;
+            lock(m_InstancesDict)
+            {
+                if(!m_ObjectInstArray.TryGetValue(partUUID, out objInstArray))
+                    return false;
+
+                if(objInstArray == null)
+                {
+                    objInstArray = RebuildObjectInstArray(partUUID);
+                    m_ObjectInstArray[partUUID] = objInstArray;
+                }
+            }
+
+            // Post event to all script instances in the object.
+            if(objInstArray.Length <= 0)
+                return false;
+            foreach(XMRInstance inst in objInstArray)
+                inst.PostEvent(parms);
+
+            return true;
+        }
+
+        public DetectParams GetDetectParams(UUID itemID, int number)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+                return null;
+            return instance.GetDetectParams(number);
+        }
+
+        public void SetMinEventDelay(UUID itemID, double delay)
+        {
+        }
+
+        public int GetStartParameter(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+                return 0;
+            return instance.StartParam;
+        }
+
+        // This is the "set running" method
+        //
+        public void SetScriptState(UUID itemID, bool state, bool self)
+        {
+            SetScriptState(itemID, state);
+        }
+        public void SetScriptState(UUID itemID, bool state)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.Running = state;
+        }
+
+        // Control display of the "running" checkbox
+        //
+        public bool GetScriptState(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+                return false;
+            return instance.Running;
+        }
+
+        public void SetState(UUID itemID, string newState)
+        {
+            TraceCalls("[YEngine]: YEngine.SetState({0},{1})", itemID.ToString(), newState);
+        }
+
+        public void ApiResetScript(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.ApiReset();
+
+        }
+
+        public void ResetScript(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                IUrlModule urlModule = m_Scene.RequestModuleInterface<IUrlModule>();
+                if(urlModule != null)
+                    urlModule.ScriptRemoved(itemID);
+
+                instance.Reset();
+            }
+        }
+
+        public IConfig Config
+        {
+            get
+            {
+                return m_Config;
+            }
+        }
+
+        public IConfigSource ConfigSource
+        {
+            get
+            {
+                return m_ConfigSource;
+            }
+        }
+
+        public string ScriptEngineName
+        {
+            get
+            {
+                return "YEngine";
+            }
+        }
+
+        public IScriptApi GetApi(UUID itemID, string name)
+        {
+            FieldInfo fi;
+            if(!m_XMRInstanceApiCtxFieldInfos.TryGetValue(name, out fi))
+                return null;
+            XMRInstance inst = GetInstance(itemID);
+            if(inst == null)
+                return null;
+            return (IScriptApi)fi.GetValue(inst);
+        }
+
+        /**
+         * @brief Get script's current state as an XML string
+         *        - called by "Take", "Take Copy" and when object deleted (ie, moved to Trash)
+         *        This includes the .state file
+         */
+        public string GetXMLState(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+                return String.Empty;
+
+            TraceCalls("[YEngine]: YEngine.GetXMLState({0})", itemID.ToString());
+
+            if(!instance.m_HasRun)
+                return String.Empty;
+
+            XmlDocument doc = new XmlDocument();
+
+            /*
+             * Set up <State Engine="YEngine" UUID="itemID" Asset="assetID"> tag.
+             */
+            XmlElement stateN = doc.CreateElement("", "State", "");
+            doc.AppendChild(stateN);
+
+            XmlAttribute engineA = doc.CreateAttribute("", "Engine", "");
+            engineA.Value = ScriptEngineName;
+            stateN.Attributes.Append(engineA);
+
+            XmlAttribute uuidA = doc.CreateAttribute("", "UUID", "");
+            uuidA.Value = itemID.ToString();
+            stateN.Attributes.Append(uuidA);
+
+            XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
+            string assetID = instance.AssetID.ToString();
+            assetA.Value = assetID;
+            stateN.Attributes.Append(assetA);
+
+            // Get <ScriptState>...</ScriptState> item that hold's script's state.
+            // This suspends the script if necessary then takes a snapshot.
+            XmlElement scriptStateN = instance.GetExecutionState(doc);
+            stateN.AppendChild(scriptStateN);
+
+            return doc.OuterXml;
+        }
+
+        // Set script's current state from an XML string
+        // - called just before a script is instantiated
+        // So we write the .state file so the .state file will be seen when 
+        // the script is instantiated.
+        public bool SetXMLState(UUID itemID, string xml)
+        {
+            XmlDocument doc = new XmlDocument();
+
+            try
+            {
+                doc.LoadXml(xml);
+            }
+            catch
+            {
+                return false;
+            }
+            TraceCalls("[YEngine]: YEngine.SetXMLState({0})", itemID.ToString());
+
+            // Make sure <State Engine="YEngine"> so we know it is in our
+            // format.
+            XmlElement stateN = (XmlElement)doc.SelectSingleNode("State");
+            if(stateN == null)
+                return false;
+
+            if(stateN.GetAttribute("Engine") != ScriptEngineName)
+                return false;
+
+            // <ScriptState>...</ScriptState> contains contents of .state file.
+            XmlElement scriptStateN = (XmlElement)stateN.SelectSingleNode("ScriptState");
+            if(scriptStateN == null)
+                return false;
+
+            string sen = stateN.GetAttribute("Engine");
+            if((sen == null) || (sen != ScriptEngineName))
+                return false;
+
+            XmlAttribute assetA = doc.CreateAttribute("", "Asset", "");
+            assetA.Value = stateN.GetAttribute("Asset");
+            scriptStateN.Attributes.Append(assetA);
+
+            // Write out the .state file with the <ScriptState ...>...</ScriptState> XML text
+            string statePath = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
+            FileStream ss = File.Create(statePath);
+            StreamWriter sw = new StreamWriter(ss);
+            sw.Write(scriptStateN.OuterXml);
+            sw.Close();
+            ss.Close();
+
+            return true;
+        }
+
+        public bool PostScriptEvent(UUID itemID, string name, Object[] p)
+        {
+            if(!m_Enabled)
+                return false;
+
+            TraceCalls("[YEngine]: YEngine.PostScriptEvent({0},{1})", itemID.ToString(), name);
+
+            return PostScriptEvent(itemID, new EventParams(name, p, zeroDetectParams));
+        }
+
+        public bool PostObjectEvent(UUID itemID, string name, Object[] p)
+        {
+            if(!m_Enabled)
+                return false;
+
+            TraceCalls("[YEngine]: YEngine.PostObjectEvent({0},{1})", itemID.ToString(), name);
+
+            SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
+            if(part == null)
+                return false;
+
+            return PostObjectEvent(part.LocalId, new EventParams(name, p, zeroDetectParams));
+        }
+
+        // about the 3523rd entrypoint for a script to put itself to sleep
+        public void SleepScript(UUID itemID, int delay)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.Sleep(delay);
+        }
+
+        // Get a script instance loaded, compiling it if necessary
+        //
+        //  localID     = the object as a whole, may contain many scripts
+        //  itemID      = this instance of the script in this object
+        //  script      = script source code
+        //  startParam  = value passed to 'on_rez' event handler
+        //  postOnRez   = true to post an 'on_rez' event to script on load
+        //  defEngine   = default script engine
+        //  stateSource = post this event to script on load
+
+        public void OnRezScript(uint localID, UUID itemID, string script,
+                int startParam, bool postOnRez, string defEngine, int stateSource)
+        {
+            SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
+            TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
+
+            if(!m_LateInit)
+            {
+                m_LateInit = true;
+                OneTimeLateInitialization();
+            }
+
+            TraceCalls("[YEngine]: OnRezScript(...,{0},...)", itemID.ToString());
+
+            // Assume script uses the default engine, whatever that is.
+            string engineName = defEngine;
+
+            // Very first line might contain "//" scriptengine ":".
+            string firstline = "";
+            if(script.StartsWith("//"))
+            {
+                int lineEnd = script.IndexOf('\n');
+                if(lineEnd > 1)
+                    firstline = script.Substring(0, lineEnd).Trim();
+                int colon = firstline.IndexOf(':');
+                if(colon >= 2)
+                {
+                    engineName = firstline.Substring(2, colon - 2).Trim();
+                    if(engineName == "")
+                        engineName = defEngine;
+                }
+            }
+
+            // Make sure the default or requested engine is us.
+            if(engineName != ScriptEngineName)
+            {
+                // Not us, if requested engine exists, silently ignore script and let
+                // requested engine handle it.
+                IScriptModule[] engines = m_Scene.RequestModuleInterfaces<IScriptModule>();
+                foreach(IScriptModule eng in engines)
+                {
+                    if(eng.ScriptEngineName == engineName)
+                        return;
+                }
+
+                // Requested engine not defined, warn on console.
+                // Then we try to handle it if we're the default engine, else we ignore it.
+                m_log.Warn("[YEngine]: " + itemID.ToString() + " requests undefined/disabled engine " + engineName);
+                m_log.Info("[YEngine]: - " + part.GetWorldPosition());
+                m_log.Info("[YEngine]: first line: " + firstline);
+                if(defEngine != ScriptEngineName)
+                {
+                    m_log.Info("[YEngine]: leaving it to the default script engine (" + defEngine + ") to process it");
+                    return;
+                }
+                m_log.Info("[YEngine]: will attempt to processing it anyway as default script engine");
+            }
+
+            // Put on object/instance lists.
+            XMRInstance instance = (XMRInstance)Activator.CreateInstance(ScriptCodeGen.xmrInstSuperType);
+            instance.m_LocalID = localID;
+            instance.m_ItemID = itemID;
+            instance.m_SourceCode = script;
+            instance.m_StartParam = startParam;
+            instance.m_PostOnRez = postOnRez;
+            instance.m_StateSource = (StateSource)stateSource;
+            instance.m_Part = part;
+            instance.m_PartUUID = part.UUID;
+            instance.m_Item = item;
+            instance.m_DescName = part.Name + ":" + item.Name;
+            instance.m_IState = XMRInstState.CONSTRUCT;
+
+            lock(m_InstancesDict)
+            {
+                m_LockedDict = "RegisterInstance";
+
+                // Insert on internal list of all scripts being handled by this engine instance.
+                m_InstancesDict[instance.m_ItemID] = instance;
+
+                // Insert on internal list of all scripts being handled by this engine instance
+                // that are part of the object.
+                List<UUID> itemIDList;
+                if(!m_ObjectItemList.TryGetValue(instance.m_PartUUID, out itemIDList))
+                {
+                    itemIDList = new List<UUID>();
+                    m_ObjectItemList[instance.m_PartUUID] = itemIDList;
+                }
+                if(!itemIDList.Contains(instance.m_ItemID))
+                {
+                    itemIDList.Add(instance.m_ItemID);
+                    m_ObjectInstArray[instance.m_PartUUID] = null;
+                }
+
+                m_LockedDict = "~RegisterInstance";
+            }
+
+            // Compile and load it.
+            lock(m_ScriptErrors)
+                m_ScriptErrors.Remove(instance.m_ItemID);
+
+            LoadThreadWork(instance);
+        }
+
+        /**
+         * @brief This routine instantiates one script.
+         */
+        private void LoadThreadWork(XMRInstance instance)
+        {
+            // Compile and load the script in memory.
+            ArrayList errors = new ArrayList();
+            Exception initerr = null;
+            try
+            {
+                instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
+            }
+            catch(Exception e1)
+            {
+                initerr = e1;
+            }
+            if((initerr != null) && !instance.m_ForceRecomp)
+            {
+                UUID itemID = instance.m_ItemID;
+                Verbose("[YEngine]: {0}/{2} first load failed ({1}), retrying after recompile",
+                        itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
+                Verbose("[YEngine]:\n{0}", initerr.ToString());
+                initerr = null;
+                errors = new ArrayList();
+                instance.m_ForceRecomp = true;
+                try
+                {
+                    instance.Initialize(this, m_ScriptBasePath, m_StackSize, m_HeapSize, errors);
+                }
+                catch(Exception e2)
+                {
+                    initerr = e2;
+                }
+            }
+            if(initerr != null)
+            {
+                UUID itemID = instance.m_ItemID;
+                Verbose("[YEngine]: Error starting script {0}/{2}: {1}",
+                                  itemID.ToString(), initerr.Message, instance.m_Item.AssetID.ToString());
+                if(initerr.Message != "compilation errors")
+                {
+                    Verbose("[YEngine]: - " + instance.m_Part.GetWorldPosition() + " " + instance.m_DescName);
+                    Verbose("[YEngine]:   exception:\n{0}", initerr.ToString());
+                }
+
+                OnRemoveScript(0, itemID);
+
+                // Post errors where GetScriptErrors() can see them.
+                if(errors.Count == 0)
+                    errors.Add(initerr.Message);
+                else
+                {
+                    foreach(Object err in errors)
+                    {
+                        if(m_ScriptDebug)
+                            m_log.DebugFormat("[YEngine]:   {0}", err.ToString());
+                    }
+                }
+                lock(m_ScriptErrors)
+                    m_ScriptErrors[instance.m_ItemID] = errors;
+
+                return;
+            }
+
+            // Tell GetScriptErrors() that we have finished compiling/loading
+            // successfully (by posting a 0 element array).
+            lock(m_ScriptErrors)
+            {
+                if(instance.m_IState != XMRInstState.CONSTRUCT)
+                    throw new Exception("bad state");
+                m_ScriptErrors[instance.m_ItemID] = noScriptErrors;
+            }
+
+            // Transition from CONSTRUCT->ONSTARTQ and give to RunScriptThread().
+            // Put it on the start queue so it will run any queued event handlers,
+            // such as state_entry() or on_rez().  If there aren't any queued, it
+            // will just go to idle state when RunOne() tries to dequeue an event.
+            lock(instance.m_QueueLock)
+            {
+                if(instance.m_IState != XMRInstState.CONSTRUCT)
+                    throw new Exception("bad state");
+                instance.m_IState = XMRInstState.ONSTARTQ;
+                if(!instance.m_Running)
+                    instance.EmptyEventQueues();
+            }
+            QueueToStart(instance);
+        }
+
+        public void OnRemoveScript(uint localID, UUID itemID)
+        {
+            TraceCalls("[YEngine]: OnRemoveScript(...,{0})", itemID.ToString());
+
+            // Remove from our list of known scripts.
+            // After this, no more events can queue because we won't be
+            // able to translate the itemID to an XMRInstance pointer.
+            XMRInstance instance = null;
+            lock(m_InstancesDict)
+            {
+                m_LockedDict = "OnRemoveScript:" + itemID.ToString();
+
+                // Tell the instance to free off everything it can.
+                if(!m_InstancesDict.TryGetValue(itemID, out instance))
+                {
+                    m_LockedDict = "~OnRemoveScript";
+                    return;
+                }
+
+                // Tell it to stop executing anything.
+                instance.suspendOnCheckRunHold = true;
+
+                // Remove it from our list of known script instances
+                // mostly so no more events can queue to it.
+                m_InstancesDict.Remove(itemID);
+
+                List<UUID> itemIDList;
+                if(m_ObjectItemList.TryGetValue(instance.m_PartUUID, out itemIDList))
+                {
+                    itemIDList.Remove(itemID);
+                    if(itemIDList.Count == 0)
+                    {
+                        m_ObjectItemList.Remove(instance.m_PartUUID);
+                        m_ObjectInstArray.Remove(instance.m_PartUUID);
+                    }
+                    else
+                        m_ObjectInstArray[instance.m_PartUUID] = null;
+                }
+
+                // Delete the .state file as any needed contents were fetched with GetXMLState()
+                // and stored on the database server.
+                string stateFileName = XMRInstance.GetStateFileName(m_ScriptBasePath, itemID);
+                File.Delete(stateFileName);
+
+                ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
+                if(handlerScriptRemoved != null)
+                    handlerScriptRemoved(itemID);
+
+                m_LockedDict = "~~OnRemoveScript";
+            }
+
+            // Free off its stack and fun things like that.
+            // If it is running, abort it.
+            instance.Dispose();
+        }
+
+        public void OnScriptReset(uint localID, UUID itemID)
+        {
+            TraceCalls("[YEngine]: YEngine.OnScriptReset({0},{1})", localID.ToString(), itemID.ToString());
+            ResetScript(itemID);
+        }
+
+        public void OnStartScript(uint localID, UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.Running = true;
+        }
+
+        public void OnStopScript(uint localID, UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.Running = false;
+        }
+
+        public void OnGetScriptRunning(IClientAPI controllingClient,
+                UUID objectID, UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                TraceCalls("[YEngine]: YEngine.OnGetScriptRunning({0},{1})", objectID.ToString(), itemID.ToString());
+
+                IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
+                if(eq == null)
+                {
+                    controllingClient.SendScriptRunningReply(objectID, itemID,
+                            instance.Running);
+                }
+                else
+                {
+                    eq.Enqueue(EventQueueHelper.ScriptRunningReplyEvent(objectID,
+                            itemID, instance.Running, true),
+                            controllingClient.AgentId);
+                }
+            }
+        }
+
+        public bool HasScript(UUID itemID, out bool running)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance == null)
+            {
+                running = true;
+                return false;
+            }
+            running = instance.Running;
+            return true;
+        }
+
+        /**
+         * @brief Called once per frame update to see if scripts have
+         *        any such work to do.
+         */
+        private void OnFrame()
+        {
+            if(m_FrameUpdateList != null)
+            {
+                ThreadStart frameupdates;
+                lock(m_FrameUpdateLock)
+                {
+                    frameupdates = m_FrameUpdateList;
+                    m_FrameUpdateList = null;
+                }
+                frameupdates();
+            }
+        }
+
+        /**
+         * @brief Add a one-shot delegate to list of things to do
+         *        synchronized with frame updates.
+         */
+        public void AddOnFrameUpdate(ThreadStart thunk)
+        {
+            lock(m_FrameUpdateLock)
+                m_FrameUpdateList += thunk;
+        }
+
+        /**
+         * @brief Gets called early as part of shutdown,
+         *        right after "Persisting changed objects" message.
+         */
+        public void OnShutdown()
+        {
+            TraceCalls("[YEngine]: YEngine.OnShutdown()");
+        }
+
+        /**
+         * @brief Queue an instance to the StartQueue so it will run.
+         *        This queue is used for instances that have just had
+         *        an event queued to them when they were previously
+         *        idle.  It must only be called by the thread that
+         *        transitioned the thread to XMRInstState.ONSTARTQ so
+         *        we don't get two threads trying to queue the same
+         *        instance to the m_StartQueue at the same time.
+         */
+        public void QueueToStart(XMRInstance inst)
+        {
+            if(inst.m_IState != XMRInstState.ONSTARTQ)
+                throw new Exception("bad state");
+
+            lock(m_StartQueue)
+                m_StartQueue.InsertTail(inst);
+
+            WakeUpOne();
+        }
+
+        /**
+         * @brief A script may be sleeping, in which case we wake it.
+         */
+        public void WakeFromSleep(XMRInstance inst)
+        {
+            // Remove from sleep queue unless someone else already woke it.
+            lock(m_SleepQueue)
+            {
+                if(inst.m_IState != XMRInstState.ONSLEEPQ)
+                    return;
+
+                m_SleepQueue.Remove(inst);
+                inst.m_IState = XMRInstState.REMDFROMSLPQ;
+            }
+
+            // Put on end of list of scripts that are ready to run.
+            lock(m_YieldQueue)
+            {
+                inst.m_IState = XMRInstState.ONYIELDQ;
+                m_YieldQueue.InsertTail(inst);
+            }
+
+            // Make sure the OS thread is running so it will see the script.
+            WakeUpOne();
+        }
+
+        /**
+         * @brief An instance has just finished running for now,
+         *        figure out what to do with it next.
+         * @param inst = instance in question, not on any queue at the moment
+         * @param newIState = its new state
+         * @returns with instance inserted onto proper queue (if any)
+         */
+        public void HandleNewIState(XMRInstance inst, XMRInstState newIState)
+        {
+            // RunOne() should have left the instance in RUNNING state.
+            if(inst.m_IState != XMRInstState.RUNNING)
+                throw new Exception("bad state");
+
+            // Now see what RunOne() wants us to do with the instance next.
+            switch(newIState)
+            {
+                // Instance has set m_SleepUntil to when it wants to sleep until.
+                // So insert instance in sleep queue by ascending wake time.
+                // Then wake the timer thread if this is the new first entry
+                // so it will reset its timer.
+                case XMRInstState.ONSLEEPQ:
+                    lock(m_SleepQueue)
+                    {
+                        XMRInstance after;
+
+                        inst.m_IState = XMRInstState.ONSLEEPQ;
+                        for(after = m_SleepQueue.PeekHead(); after != null; after = after.m_NextInst)
+                        {
+                            if(after.m_SleepUntil > inst.m_SleepUntil)
+                                break;
+                        }
+                        m_SleepQueue.InsertBefore(inst, after);
+                        if(m_SleepQueue.PeekHead() == inst)
+                            Monitor.Pulse(m_SleepQueue);
+                    }
+                    break;
+
+                // Instance just took a long time to run and got wacked by the
+                // slicer.  So put on end of yield queue to let someone else
+                // run.  If there is no one else, it will run again right away.
+                case XMRInstState.ONYIELDQ:
+                    lock(m_YieldQueue)
+                    {
+                        inst.m_IState = XMRInstState.ONYIELDQ;
+                        m_YieldQueue.InsertTail(inst);
+                    }
+                    break;
+
+                // Instance finished executing an event handler.  So if there is
+                // another event queued for it, put it on the start queue so it
+                // will process the new event.  Otherwise, mark it idle and the
+                // next event to queue to it will start it up.
+                case XMRInstState.FINISHED:
+                    Monitor.Enter(inst.m_QueueLock);
+                    if(!inst.m_Suspended && (inst.m_EventQueue.Count > 0))
+                    {
+                        inst.m_IState = XMRInstState.ONSTARTQ;
+                        Monitor.Exit(inst.m_QueueLock);
+                        lock(m_StartQueue)
+                            m_StartQueue.InsertTail(inst);
+                    }
+                    else
+                    {
+                        inst.m_IState = XMRInstState.IDLE;
+                        Monitor.Exit(inst.m_QueueLock);
+                    }
+                    break;
+
+                // Its m_SuspendCount > 0.
+                // Don't put it on any queue and it won't run.
+                // Since it's not IDLE, even queuing an event won't start it.
+                case XMRInstState.SUSPENDED:
+                    inst.m_IState = XMRInstState.SUSPENDED;
+                    break;
+
+                // It has been disposed of.
+                // Just set the new state and all refs should theoretically drop off
+                // as the instance is no longer in any list.
+                case XMRInstState.DISPOSED:
+                    inst.m_IState = XMRInstState.DISPOSED;
+                    break;
+
+                // RunOne returned something bad.
+                default:
+                    throw new Exception("bad new state");
+            }
+        }
+
+        /**
+         * @brief Thread that moves instances from the Sleep queue to the Yield queue.
+         */
+        private void RunSleepThread()
+        {
+            double deltaTS;
+            int deltaMS;
+            XMRInstance inst;
+
+            while(true)
+            {
+                lock(m_SleepQueue)
+                {
+                    // Wait here until there is a script on the timer queue that has expired.
+                    while(true)
+                    {
+                        UpdateMyThread();
+                        if(m_Exiting)
+                        {
+                            MyThreadExiting();
+                            return;
+                        }
+                        inst = m_SleepQueue.PeekHead();
+                        if(inst == null)
+                        {
+                            Monitor.Wait(m_SleepQueue, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
+                            continue;
+                        }
+                        if(inst.m_IState != XMRInstState.ONSLEEPQ)
+                            throw new Exception("bad state");
+                        deltaTS = (inst.m_SleepUntil - DateTime.UtcNow).TotalMilliseconds;
+                        if(deltaTS <= 0.0)
+                            break;
+                        deltaMS = Int32.MaxValue;
+                        if(deltaTS < Int32.MaxValue)
+                            deltaMS = (int)deltaTS;
+                        if(deltaMS > Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2)
+                            deltaMS = Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2;
+
+                        Monitor.Wait(m_SleepQueue, deltaMS);
+                    }
+
+                    // Remove the expired entry from the timer queue.
+                    m_SleepQueue.RemoveHead();
+                    inst.m_IState = XMRInstState.REMDFROMSLPQ;
+                }
+
+                // Post the script to the yield queue so it will run and wake a script thread to run it.
+                lock(m_YieldQueue)
+                {
+                    inst.m_IState = XMRInstState.ONYIELDQ;
+                    m_YieldQueue.InsertTail(inst);
+                }
+                WakeUpOne();
+            }
+        }
+
+        public void Suspend(UUID itemID, int ms)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.Sleep(ms);
+        }
+
+        public void Die(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                TraceCalls("[YEngine]: YEngine.Die({0})", itemID.ToString());
+                instance.Die();
+            }
+        }
+
+        /**
+         * @brief Get specific script instance for which OnRezScript()
+         *        has been called for an YEngine script, and that
+         *        OnRemoveScript() has not been called since.
+         * @param itemID = as passed to OnRezScript() identifying a specific script instance
+         * @returns null: not one of our scripts (maybe XEngine etc)
+         *          else: points to the script instance
+         */
+        public XMRInstance GetInstance(UUID itemID)
+        {
+            XMRInstance instance;
+            lock(m_InstancesDict)
+            {
+                if(!m_InstancesDict.TryGetValue(itemID, out instance))
+                    instance = null;
+            }
+            return instance;
+        }
+
+        // Called occasionally to write script state to .state file so the
+        // script will restart from its last known state if the region crashes
+        // and gets restarted.
+        private void DoMaintenance(object source, ElapsedEventArgs e)
+        {
+            XMRInstance[] instanceArray;
+
+            lock(m_InstancesDict)
+                instanceArray = System.Linq.Enumerable.ToArray(m_InstancesDict.Values);
+
+            foreach(XMRInstance ins in instanceArray)
+            {
+                // Don't save attachments
+                if(ins.m_Part.ParentGroup.IsAttachment)
+                    continue;
+                ins.GetExecutionState(new XmlDocument());
+            }
+        }
+
+        /**
+         * @brief Retrieve errors generated by a previous call to OnRezScript().
+         *        We are guaranteed this routine will not be called before the
+         *        corresponding OnRezScript() has returned.  It blocks until the
+         *        compile has completed.
+         */
+        public ArrayList GetScriptErrors(UUID itemID)
+        {
+            ArrayList errors;
+
+            lock(m_ScriptErrors)
+            {
+                while(!m_ScriptErrors.TryGetValue(itemID, out errors))
+                {
+                    Monitor.Wait(m_ScriptErrors);
+                }
+                m_ScriptErrors.Remove(itemID);
+            }
+            return errors;
+        }
+
+        /**
+         * @brief Return a list of all script execution times.
+         */
+        public Dictionary<uint, float> GetObjectScriptsExecutionTimes()
+        {
+            Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
+            lock(m_InstancesDict)
+            {
+                foreach(XMRInstance instance in m_InstancesDict.Values)
+                {
+                    uint rootLocalID = instance.m_Part.ParentGroup.LocalId;
+                    float oldTotal;
+                    if(!topScripts.TryGetValue(rootLocalID, out oldTotal))
+                        oldTotal = 0;
+
+                    topScripts[rootLocalID] = (float)instance.m_CPUTime + oldTotal;
+                }
+            }
+            return topScripts;
+        }
+
+        /**
+         * @brief A float the value is a representative execution time in
+         *        milliseconds of all scripts in the link set.
+         * @param itemIDs = list of scripts in the link set
+         * @returns milliseconds for all those scripts
+         */
+        public float GetScriptExecutionTime(List<UUID> itemIDs)
+        {
+            if((itemIDs == null) || (itemIDs.Count == 0))
+                return 0;
+
+            float time = 0;
+            foreach(UUID itemID in itemIDs)
+            {
+                XMRInstance instance = GetInstance(itemID);
+                if((instance != null) && instance.Running)
+                    time += (float)instance.m_CPUTime;
+            }
+            return time;
+        }
+
+        /**
+         * @brief Block script from dequeuing events.
+         */
+        public void SuspendScript(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                TraceCalls("[YEngine]: YEngine.SuspendScript({0})", itemID.ToString());
+                instance.SuspendIt();
+            }
+        }
+
+        /**
+         * @brief Allow script to dequeue events.
+         */
+        public void ResumeScript(UUID itemID)
+        {
+            XMRInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                TraceCalls("[YEngine]: YEngine.ResumeScript({0})", itemID.ToString());
+                instance.ResumeIt();
+            }
+            else
+            {
+                // probably an XEngine script
+            }
+        }
+
+        /**
+         * @brief Rebuild m_ObjectInstArray[partUUID] from m_ObjectItemList[partUUID]
+         * @param partUUID = which object in scene to rebuild for
+         */
+        private XMRInstance[] RebuildObjectInstArray(UUID partUUID)
+        {
+            List<UUID> itemIDList = m_ObjectItemList[partUUID];
+            int n = 0;
+            foreach(UUID itemID in itemIDList)
+            {
+                if(m_InstancesDict.ContainsKey(itemID))
+                    n++;
+            }
+
+            XMRInstance[] a = new XMRInstance[n];
+            n = 0;
+            foreach(UUID itemID in itemIDList)
+            {
+                if(m_InstancesDict.TryGetValue(itemID, out a[n]))
+                    n++;
+            }
+            m_ObjectInstArray[partUUID] = a;
+            return a;
+        }
+
+        public void TraceCalls(string format, params object[] args)
+        {
+            if(m_TraceCalls)
+                m_log.DebugFormat(format, args);
+        }
+        public void Verbose(string format, params object[] args)
+        {
+            if(m_Verbose)
+                m_log.DebugFormat(format, args);
+        }
+
+        /**
+         * @brief Manage our threads.
+         */
+        public static Thread StartMyThread(ThreadStart start, string name, ThreadPriority priority)
+        {
+            m_log.Debug("[YEngine]: starting thread " + name);
+            Thread thread = WorkManager.StartThread(start, name, priority, true, false, false);
+            return thread;
+        }
+
+        public static void UpdateMyThread()
+        {
+            Watchdog.UpdateThread();
+        }
+
+        public static void MyThreadExiting()
+        {
+            Watchdog.RemoveThread(true);
+        }
+    }
+}

+ 56 - 48
OpenSim/Region/ScriptEngine/XMREngine/XMREvents.cs → OpenSim/Region/ScriptEngine/YEngine/XMREvents.cs

@@ -45,41 +45,41 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /// <summary>
     /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
     /// </summary>
-    public partial class XMREngine
+    public partial class Yengine
     {
         public static readonly object[] zeroObjectArray = new object[0];
         public static readonly object[] oneObjectArrayOne = new object[1] { 1 };
 
         private void InitEvents()
         {
-            m_log.Info("[XMREngine] Hooking up to server events");
-            this.World.EventManager.OnAttach                    += attach;
-            this.World.EventManager.OnObjectGrab                += touch_start;
-            this.World.EventManager.OnObjectGrabbing            += touch;
-            this.World.EventManager.OnObjectDeGrab              += touch_end;
-            this.World.EventManager.OnScriptChangedEvent        += changed;
-            this.World.EventManager.OnScriptAtTargetEvent       += at_target;
-            this.World.EventManager.OnScriptNotAtTargetEvent    += not_at_target;
-            this.World.EventManager.OnScriptAtRotTargetEvent    += at_rot_target;
+            m_log.Info("[YEngine] Hooking up to server events");
+            this.World.EventManager.OnAttach += attach;
+            this.World.EventManager.OnObjectGrab += touch_start;
+            this.World.EventManager.OnObjectGrabbing += touch;
+            this.World.EventManager.OnObjectDeGrab += touch_end;
+            this.World.EventManager.OnScriptChangedEvent += changed;
+            this.World.EventManager.OnScriptAtTargetEvent += at_target;
+            this.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
+            this.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target;
             this.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target;
-            this.World.EventManager.OnScriptMovingStartEvent    += moving_start;
-            this.World.EventManager.OnScriptMovingEndEvent      += moving_end;
-            this.World.EventManager.OnScriptControlEvent        += control;
-            this.World.EventManager.OnScriptColliderStart       += collision_start;
-            this.World.EventManager.OnScriptColliding           += collision;
-            this.World.EventManager.OnScriptCollidingEnd        += collision_end;
-            this.World.EventManager.OnScriptLandColliderStart   += land_collision_start;
-            this.World.EventManager.OnScriptLandColliding       += land_collision;
-            this.World.EventManager.OnScriptLandColliderEnd     += land_collision_end;
-            IMoneyModule money=this.World.RequestModuleInterface<IMoneyModule>();
-            if (money != null)
+            this.World.EventManager.OnScriptMovingStartEvent += moving_start;
+            this.World.EventManager.OnScriptMovingEndEvent += moving_end;
+            this.World.EventManager.OnScriptControlEvent += control;
+            this.World.EventManager.OnScriptColliderStart += collision_start;
+            this.World.EventManager.OnScriptColliding += collision;
+            this.World.EventManager.OnScriptCollidingEnd += collision_end;
+            this.World.EventManager.OnScriptLandColliderStart += land_collision_start;
+            this.World.EventManager.OnScriptLandColliding += land_collision;
+            this.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
+            IMoneyModule money = this.World.RequestModuleInterface<IMoneyModule>();
+            if(money != null)
             {
-                money.OnObjectPaid+=HandleObjectPaid;
+                money.OnObjectPaid += HandleObjectPaid;
             }
         }
 
@@ -106,15 +106,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             SceneObjectPart part =
                     this.World.GetSceneObjectPart(objectID);
 
-            if (part == null)
+            if(part == null)
                 return;
 
-            if ((part.ScriptEvents & scriptEvents.money) == 0)
+            if((part.ScriptEvents & scriptEvents.money) == 0)
                 part = part.ParentGroup.RootPart;
 
-            Verbose ("Paid: " + objectID + " from " + agentID + ", amount " + amount);
+            Verbose("Paid: " + objectID + " from " + agentID + ", amount " + amount);
 
-            if (part != null)
+            if(part != null)
             {
                 money(part.LocalId, agentID, amount, det);
             }
@@ -141,7 +141,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             touches(localID, originalID, offsetPos, remoteClient, surfaceArgs, "touch");
         }
 
-        private static Vector3 zeroVec3 = new Vector3(0,0,0);
+        private static Vector3 zeroVec3 = new Vector3(0, 0, 0);
         public void touch_end(uint localID, uint originalID, IClientAPI remoteClient,
                               SurfaceTouchEventArgs surfaceArgs)
         {
@@ -152,10 +152,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs, string eventname)
         {
             SceneObjectPart part;
-            if (originalID == 0) {
+            if(originalID == 0)
+            {
                 part = this.World.GetSceneObjectPart(localID);
-                if (part == null) return;
-            } else {
+                if(part == null)
+                    return;
+            }
+            else
+            {
                 part = this.World.GetSceneObjectPart(originalID);
             }
 
@@ -167,7 +171,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                                            offsetPos.Z);
             det.LinkNum = part.LinkNum;
 
-            if (surfaceArgs != null) {
+            if(surfaceArgs != null)
+            {
                 det.SurfaceTouchArgs = surfaceArgs;
             }
 
@@ -182,7 +187,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             int ch = (int)change;
             // Add to queue for all scripts in localID, Object pass change.
             this.PostObjectEvent(localID, new EventParams(
-                    "changed",new object[] { ch },
+                    "changed", new object[] { ch },
                     zeroDetectParams));
         }
 
@@ -216,15 +221,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         private void collisions(uint localID, ColliderArgs col, string eventname)
         {
             int dc = col.Colliders.Count;
-            if (dc > 0) {
+            if(dc > 0)
+            {
                 DetectParams[] det = new DetectParams[dc];
                 int i = 0;
-                foreach (DetectedObject detobj in col.Colliders) {
+                foreach(DetectedObject detobj in col.Colliders)
+                {
                     DetectParams d = new DetectParams();
                     det[i++] = d;
 
                     d.Key = detobj.keyUUID;
-                    d.Populate (this.World);
+                    d.Populate(this.World);
 
                     /* not done by XEngine...
                     d.Position = detobj.posVector;
@@ -257,12 +264,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
         private void land_collisions(uint localID, ColliderArgs col, string eventname)
         {
-            foreach (DetectedObject detobj in col.Colliders) {
+            foreach(DetectedObject detobj in col.Colliders)
+            {
                 LSL_Vector vec = new LSL_Vector(detobj.posVector.X,
                                                 detobj.posVector.Y,
                                                 detobj.posVector.Z);
-                EventParams eps = new EventParams(eventname, 
-                                                  new Object[] { vec }, 
+                EventParams eps = new EventParams(eventname,
+                                                  new Object[] { vec },
                                                   zeroDetectParams);
                 this.PostObjectEvent(localID, eps);
             }
@@ -274,7 +282,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void control(UUID itemID, UUID agentID, uint held, uint change)
         {
             this.PostScriptEvent(itemID, new EventParams(
-                    "control",new object[] {
+                    "control", new object[] {
                     agentID.ToString(),
                     (int)held,
                     (int)change},
@@ -285,7 +293,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 string address, string subject, string message, int numLeft)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "email",new object[] {
+                    "email", new object[] {
                     timeSent,
                     address,
                     subject,
@@ -308,18 +316,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void not_at_target(uint localID)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "not_at_target",zeroObjectArray,
+                    "not_at_target", zeroObjectArray,
                     zeroDetectParams));
         }
 
         public void at_rot_target(uint localID, uint handle, OpenMetaverse.Quaternion targetrot, OpenMetaverse.Quaternion atrot)
         {
             this.PostObjectEvent(
-                localID, 
+                localID,
                 new EventParams(
                     "at_rot_target",
                     new object[] {
-                        new LSL_Integer(handle), 
+                        new LSL_Integer(handle),
                         new LSL_Rotation(targetrot.X, targetrot.Y, targetrot.Z, targetrot.W),
                         new LSL_Rotation(atrot.X, atrot.Y, atrot.Z, atrot.W)
                     },
@@ -331,7 +339,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void not_at_rot_target(uint localID)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "not_at_rot_target",zeroObjectArray,
+                    "not_at_rot_target", zeroObjectArray,
                     zeroDetectParams));
         }
 
@@ -340,7 +348,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void attach(uint localID, UUID itemID, UUID avatar)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "attach",new object[] {
+                    "attach", new object[] {
                     avatar.ToString() },
                     zeroDetectParams));
         }
@@ -351,14 +359,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void moving_start(uint localID)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "moving_start",zeroObjectArray,
+                    "moving_start", zeroObjectArray,
                     zeroDetectParams));
         }
 
         public void moving_end(uint localID)
         {
             this.PostObjectEvent(localID, new EventParams(
-                    "moving_end",zeroObjectArray,
+                    "moving_end", zeroObjectArray,
                     zeroDetectParams));
         }
 

+ 101 - 73
OpenSim/Region/ScriptEngine/XMREngine/XMRHeapTracker.cs → OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs

@@ -37,7 +37,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /**
      * One instance of this class for lsl base objects that take a variable
@@ -48,32 +48,35 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
      * Note that the xmr arrays and script-defined objects have their own
      * heap tracking built in so do not need any of this stuff.
      */
-    public class HeapTrackerBase {
+    public class HeapTrackerBase
+    {
         protected int usage;                    // num bytes used by object
         protected XMRInstAbstract instance;     // what script it is in
 
-        public HeapTrackerBase (XMRInstAbstract inst)
+        public HeapTrackerBase(XMRInstAbstract inst)
         {
-            if (inst == null) throw new ArgumentNullException ("inst");
+            if(inst == null)
+                throw new ArgumentNullException("inst");
             instance = inst;
         }
 
-        ~HeapTrackerBase ()
+        ~HeapTrackerBase()
         {
-            usage = instance.UpdateHeapUse (usage, 0);
+            usage = instance.UpdateHeapUse(usage, 0);
         }
     }
 
     /**
      * Wrapper around lists to keep track of how much memory they use.
      */
-    public class HeapTrackerList : HeapTrackerBase {
-        private static FieldInfo listValueField = typeof (HeapTrackerList).GetField ("value");
-        private static MethodInfo listSaveMethod = typeof (HeapTrackerList).GetMethod ("Save");
+    public class HeapTrackerList: HeapTrackerBase
+    {
+        private static FieldInfo listValueField = typeof(HeapTrackerList).GetField("value");
+        private static MethodInfo listSaveMethod = typeof(HeapTrackerList).GetMethod("Save");
 
         public LSL_List value;
 
-        public HeapTrackerList (XMRInstAbstract inst) : base (inst) { }
+        public HeapTrackerList(XMRInstAbstract inst) : base(inst) { }
 
         // generate CIL code to pop the value from the CIL stack
         //  input:
@@ -83,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   new value popped from CIL stack
         //   heap usage updated
-        public static void GenPop (Token errorAt, ScriptMyILGen ilGen)
+        public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
         {
             ilGen.Emit(errorAt, OpCodes.Call, listSaveMethod);
         }
@@ -95,21 +98,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   value pushed on CIL stack replacing 'this' pointer
         //   returns typeof value pushed on stack
-        public static Type GenPush (Token errorAt, ScriptMyILGen ilGen)
+        public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
         {
-            ilGen.Emit (errorAt, OpCodes.Ldfld, listValueField);
-            return typeof (LSL_List);
+            ilGen.Emit(errorAt, OpCodes.Ldfld, listValueField);
+            return typeof(LSL_List);
         }
 
-        public void Save (LSL_List lis)
+        public void Save(LSL_List lis)
         {
-            int newuse = Size (lis);
-            usage = instance.UpdateHeapUse (usage, newuse);
+            int newuse = Size(lis);
+            usage = instance.UpdateHeapUse(usage, newuse);
             value = lis;
         }
 
         //private static int counter = 5;
-        public static int Size (LSL_List lis)
+        public static int Size(LSL_List lis)
         {
             // VS2017 in debug mode seems to have a problem running this statement quickly:
             //SLOW: return (!typeof(LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size;
@@ -120,9 +123,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
             // VS2017 in debug mode seems content to run this quickly though:
 
-            try {
+            try
+            {
                 return lis.Size;
-            } catch {
+            }
+            catch
+            {
                 return 0;
             }
         }
@@ -131,22 +137,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
     /**
      * Wrapper around objects to keep track of how much memory they use.
      */
-    public class HeapTrackerObject : HeapTrackerBase {
-        private static FieldInfo objectValueField = typeof (HeapTrackerObject).GetField ("value");
-        private static MethodInfo objectSaveMethod = typeof (HeapTrackerObject).GetMethod ("Save");
+    public class HeapTrackerObject: HeapTrackerBase
+    {
+        private static FieldInfo objectValueField = typeof(HeapTrackerObject).GetField("value");
+        private static MethodInfo objectSaveMethod = typeof(HeapTrackerObject).GetMethod("Save");
 
         public const int HT_CHAR = 2;
         public const int HT_DELE = 8;
         public const int HT_DOUB = 8;
         public const int HT_SING = 4;
         public const int HT_SFLT = 4;
-        public const int HT_INT  = 4;
-        public const int HT_VEC  = HT_DOUB * 3;
-        public const int HT_ROT  = HT_DOUB * 4;
+        public const int HT_INT = 4;
+        public const int HT_VEC = HT_DOUB * 3;
+        public const int HT_ROT = HT_DOUB * 4;
 
         public object value;
 
-        public HeapTrackerObject (XMRInstAbstract inst) : base (inst) { }
+        public HeapTrackerObject(XMRInstAbstract inst) : base(inst) { }
 
         // generate CIL code to pop the value from the CIL stack
         //  input:
@@ -156,7 +163,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   new value popped from CIL stack
         //   heap usage updated
-        public static void GenPop (Token errorAt, ScriptMyILGen ilGen)
+        public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
         {
             ilGen.Emit(errorAt, OpCodes.Call, objectSaveMethod);
         }
@@ -168,67 +175,88 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   value pushed on CIL stack replacing 'this' pointer
         //   returns typeof value pushed on stack
-        public static Type GenPush (Token errorAt, ScriptMyILGen ilGen)
+        public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
         {
-            ilGen.Emit (errorAt, OpCodes.Ldfld, objectValueField);
-            return typeof (object);
+            ilGen.Emit(errorAt, OpCodes.Ldfld, objectValueField);
+            return typeof(object);
         }
 
-        public void Save (object obj)
+        public void Save(object obj)
         {
-            int newuse = Size (obj);
-            usage = instance.UpdateHeapUse (usage, newuse);
+            int newuse = Size(obj);
+            usage = instance.UpdateHeapUse(usage, newuse);
             value = obj;
         }
 
         // public so it can be used by XMRArray
-        public static int Size (object obj)
+        public static int Size(object obj)
         {
-            if (obj == null) return 0;
-
-            if (obj is char)            return HT_CHAR;
-            if (obj is Delegate)        return HT_DELE;
-            if (obj is double)          return HT_DOUB;
-            if (obj is float)           return HT_SING;
-            if (obj is int)             return HT_INT;
-            if (obj is LSL_Float)       return HT_SFLT;
-            if (obj is LSL_Integer)     return HT_INT;
-            if (obj is LSL_List)        return ((LSL_List)obj).Size;
-            if (obj is LSL_Rotation)    return HT_ROT;
-            if (obj is LSL_String)      return ((LSL_String)obj).m_string.Length * HT_CHAR;
-            if (obj is LSL_Vector)      return HT_VEC;
-            if (obj is string)          return ((string)obj).Length * HT_CHAR;
-            if (obj is XMR_Array)       return 0;
-            if (obj is XMRArrayListKey) return ((XMRArrayListKey)obj).Size;
-            if (obj is XMRSDTypeClObj)  return 0;
-
-            if (obj is Array) {
+            if(obj == null)
+                return 0;
+
+            if(obj is char)
+                return HT_CHAR;
+            if(obj is Delegate)
+                return HT_DELE;
+            if(obj is double)
+                return HT_DOUB;
+            if(obj is float)
+                return HT_SING;
+            if(obj is int)
+                return HT_INT;
+            if(obj is LSL_Float)
+                return HT_SFLT;
+            if(obj is LSL_Integer)
+                return HT_INT;
+            if(obj is LSL_List)
+                return ((LSL_List)obj).Size;
+            if(obj is LSL_Rotation)
+                return HT_ROT;
+            if(obj is LSL_String)
+                return ((LSL_String)obj).m_string.Length * HT_CHAR;
+            if(obj is LSL_Vector)
+                return HT_VEC;
+            if(obj is string)
+                return ((string)obj).Length * HT_CHAR;
+            if(obj is XMR_Array)
+                return 0;
+            if(obj is XMRArrayListKey)
+                return ((XMRArrayListKey)obj).Size;
+            if(obj is XMRSDTypeClObj)
+                return 0;
+
+            if(obj is Array)
+            {
                 Array ar = (Array)obj;
                 int len = ar.Length;
-                if (len == 0) return 0;
-                Type et = ar.GetType ().GetElementType ();
-                if (et.IsValueType) return Size (ar.GetValue (0)) * len;
+                if(len == 0)
+                    return 0;
+                Type et = ar.GetType().GetElementType();
+                if(et.IsValueType)
+                    return Size(ar.GetValue(0)) * len;
                 int size = 0;
-                for (int i = 0; i < len; i ++) {
-                    size += Size (ar.GetValue (i));
+                for(int i = 0; i < len; i++)
+                {
+                    size += Size(ar.GetValue(i));
                 }
                 return size;
             }
 
-            throw new Exception ("unknown size of type " + obj.GetType ().Name);
+            throw new Exception("unknown size of type " + obj.GetType().Name);
         }
     }
 
     /**
      * Wrapper around strings to keep track of how much memory they use.
      */
-    public class HeapTrackerString : HeapTrackerBase {
-        private static FieldInfo stringValueField = typeof (HeapTrackerString).GetField ("value");
-        private static MethodInfo stringSaveMethod = typeof (HeapTrackerString).GetMethod ("Save");
+    public class HeapTrackerString: HeapTrackerBase
+    {
+        private static FieldInfo stringValueField = typeof(HeapTrackerString).GetField("value");
+        private static MethodInfo stringSaveMethod = typeof(HeapTrackerString).GetMethod("Save");
 
         public string value;
 
-        public HeapTrackerString (XMRInstAbstract inst) : base (inst) { }
+        public HeapTrackerString(XMRInstAbstract inst) : base(inst) { }
 
         // generate CIL code to pop the value from the CIL stack
         //  input:
@@ -238,9 +266,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   new value popped from CIL stack
         //   heap usage updated
-        public static void GenPop (Token errorAt, ScriptMyILGen ilGen)
+        public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
         {
-            ilGen.Emit (errorAt, OpCodes.Call, stringSaveMethod);
+            ilGen.Emit(errorAt, OpCodes.Call, stringSaveMethod);
         }
 
         // generate CIL code to push the value on the CIL stack
@@ -250,20 +278,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //   'this' pointer popped from stack
         //   value pushed on CIL stack replacing 'this' pointer
         //   returns typeof value pushed on stack
-        public static Type GenPush (Token errorAt, ScriptMyILGen ilGen)
+        public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
         {
-            ilGen.Emit (errorAt, OpCodes.Ldfld, stringValueField);
-            return typeof (string);
+            ilGen.Emit(errorAt, OpCodes.Ldfld, stringValueField);
+            return typeof(string);
         }
 
-        public void Save (string str)
+        public void Save(string str)
         {
-            int newuse = Size (str);
-            usage = instance.UpdateHeapUse (usage, newuse);
+            int newuse = Size(str);
+            usage = instance.UpdateHeapUse(usage, newuse);
             value = str;
         }
 
-        public static int Size (string str)
+        public static int Size(string str)
         {
             return (str == null) ? 0 : str.Length * HeapTrackerObject.HT_CHAR;
         }

+ 2348 - 0
OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs

@@ -0,0 +1,2348 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Reflection.Emit;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Threading;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+    public class XMRInstArrays
+    {
+        public XMR_Array[] iarArrays;
+        public char[] iarChars;
+        public double[] iarFloats;
+        public int[] iarIntegers;
+        public LSL_List[] iarLists;
+        public object[] iarObjects;
+        public LSL_Rotation[] iarRotations;
+        public string[] iarStrings;
+        public LSL_Vector[] iarVectors;
+        public XMRSDTypeClObj[] iarSDTClObjs;
+        public Delegate[][] iarSDTIntfObjs;
+
+        private XMRInstAbstract instance;
+        private int heapUse;
+
+        private static readonly XMR_Array[] noArrays = new XMR_Array[0];
+        private static readonly char[] noChars = new char[0];
+        private static readonly double[] noFloats = new double[0];
+        private static readonly int[] noIntegers = new int[0];
+        private static readonly LSL_List[] noLists = new LSL_List[0];
+        private static readonly object[] noObjects = new object[0];
+        private static readonly LSL_Rotation[] noRotations = new LSL_Rotation[0];
+        private static readonly string[] noStrings = new string[0];
+        private static readonly LSL_Vector[] noVectors = new LSL_Vector[0];
+        private static readonly XMRSDTypeClObj[] noSDTClObjs = new XMRSDTypeClObj[0];
+        private static readonly Delegate[][] noSDTIntfObjs = new Delegate[0][];
+
+        public XMRInstArrays(XMRInstAbstract inst)
+        {
+            instance = inst;
+        }
+
+        ~XMRInstArrays()
+        {
+            heapUse = instance.UpdateHeapUse(heapUse, 0);
+        }
+
+        public void AllocVarArrays(XMRInstArSizes ars)
+        {
+            ClearOldArrays();
+
+            heapUse = instance.UpdateHeapUse(heapUse,
+                ars.iasChars * HeapTrackerObject.HT_CHAR +
+                ars.iasFloats * HeapTrackerObject.HT_SFLT +
+                ars.iasIntegers * HeapTrackerObject.HT_INT +
+                ars.iasRotations * HeapTrackerObject.HT_ROT +
+                ars.iasVectors * HeapTrackerObject.HT_VEC +
+                ars.iasSDTIntfObjs * HeapTrackerObject.HT_DELE);
+
+            iarArrays = (ars.iasArrays > 0) ? new XMR_Array[ars.iasArrays] : noArrays;
+            iarChars = (ars.iasChars > 0) ? new char[ars.iasChars] : noChars;
+            iarFloats = (ars.iasFloats > 0) ? new double[ars.iasFloats] : noFloats;
+            iarIntegers = (ars.iasIntegers > 0) ? new int[ars.iasIntegers] : noIntegers;
+            iarLists = (ars.iasLists > 0) ? new LSL_List[ars.iasLists] : noLists;
+            iarObjects = (ars.iasObjects > 0) ? new object[ars.iasObjects] : noObjects;
+            iarRotations = (ars.iasRotations > 0) ? new LSL_Rotation[ars.iasRotations] : noRotations;
+            iarStrings = (ars.iasStrings > 0) ? new string[ars.iasStrings] : noStrings;
+            iarVectors = (ars.iasVectors > 0) ? new LSL_Vector[ars.iasVectors] : noVectors;
+            iarSDTClObjs = (ars.iasSDTClObjs > 0) ? new XMRSDTypeClObj[ars.iasSDTClObjs] : noSDTClObjs;
+            iarSDTIntfObjs = (ars.iasSDTIntfObjs > 0) ? new Delegate[ars.iasSDTIntfObjs][] : noSDTIntfObjs;
+        }
+
+        /**
+         * @brief Do not write directly to iarLists[index], rather use this method.
+         */
+        public void PopList(int index, LSL_List lis)
+        {
+            LSL_List old = iarLists[index];
+            int newheapuse = heapUse + HeapTrackerList.Size(lis) - HeapTrackerList.Size(old);
+            heapUse = instance.UpdateHeapUse(heapUse, newheapuse);
+            iarLists[index] = lis;
+        }
+
+        /**
+         * @brief Do not write directly to iarObjects[index], rather use this method.
+         */
+        public void PopObject(int index, object obj)
+        {
+            object old = iarObjects[index];
+            int newheapuse = heapUse + HeapTrackerObject.Size(obj) - HeapTrackerObject.Size(old);
+            heapUse = instance.UpdateHeapUse(heapUse, newheapuse);
+            iarObjects[index] = obj;
+        }
+
+        /**
+         * @brief Do not write directly to iarStrings[index], rather use this method.
+         */
+        public void PopString(int index, string str)
+        {
+            string old = iarStrings[index];
+            int newheapuse = heapUse + HeapTrackerString.Size(str) - HeapTrackerString.Size(old);
+            heapUse = instance.UpdateHeapUse(heapUse, newheapuse);
+            iarStrings[index] = str;
+        }
+
+        /**
+         * @brief Write all arrays out to a file.
+         */
+        public delegate void Sender(object value);
+        public void SendArrays(Sender sender)
+        {
+            sender(iarArrays);
+            sender(iarChars);
+            sender(iarFloats);
+            sender(iarIntegers);
+            sender(iarLists);
+            sender(iarObjects);
+            sender(iarRotations);
+            sender(iarStrings);
+            sender(iarVectors);
+            sender(iarSDTClObjs);
+            sender(iarSDTIntfObjs);
+        }
+
+        /**
+         * @brief Read all arrays in from a file.
+         */
+        public delegate object Recver();
+        public void RecvArrays(Recver recver)
+        {
+            ClearOldArrays();
+
+            iarArrays = (XMR_Array[])recver();
+            char[] chrs = (char[])recver();
+            double[] flts = (double[])recver();
+            int[] ints = (int[])recver();
+            LSL_List[] liss = (LSL_List[])recver();
+            object[] objs = (object[])recver();
+            LSL_Rotation[] rots = (LSL_Rotation[])recver();
+            string[] strs = (string[])recver();
+            LSL_Vector[] vecs = (LSL_Vector[])recver();
+            iarSDTClObjs = (XMRSDTypeClObj[])recver();
+            Delegate[][] dels = (Delegate[][])recver();
+
+            int newheapuse = heapUse;
+
+            // value types simply are the size of the value * number of values
+            newheapuse += chrs.Length * HeapTrackerObject.HT_CHAR;
+            newheapuse += flts.Length * HeapTrackerObject.HT_SFLT;
+            newheapuse += ints.Length * HeapTrackerObject.HT_INT;
+            newheapuse += rots.Length * HeapTrackerObject.HT_ROT;
+            newheapuse += vecs.Length * HeapTrackerObject.HT_VEC;
+            newheapuse += dels.Length * HeapTrackerObject.HT_DELE;
+
+            // lists, objects, strings are the sum of the size of each element
+            foreach(LSL_List lis in liss)
+                newheapuse += HeapTrackerList.Size(lis);
+
+            foreach(object obj in objs)
+                newheapuse += HeapTrackerObject.Size(obj);
+
+            foreach(string str in strs)
+                newheapuse += HeapTrackerString.Size(str);
+
+            // others (XMR_Array, XMRSDTypeClObj) keep track of their own heap usage
+
+            // update script heap usage, throwing an exception before finalizing changes
+            heapUse = instance.UpdateHeapUse(heapUse, newheapuse);
+
+            iarChars = chrs;
+            iarFloats = flts;
+            iarIntegers = ints;
+            iarLists = liss;
+            iarObjects = objs;
+            iarRotations = rots;
+            iarStrings = strs;
+            iarVectors = vecs;
+            iarSDTIntfObjs = dels;
+        }
+
+        private void ClearOldArrays()
+        {
+            int newheapuse = heapUse;
+
+            iarArrays = null;
+            if(iarChars != null)
+            {
+                newheapuse -= iarChars.Length * HeapTrackerObject.HT_CHAR;
+                iarChars = null;
+            }
+            if(iarFloats != null)
+            {
+                newheapuse -= iarFloats.Length * HeapTrackerObject.HT_SFLT;
+                iarFloats = null;
+            }
+            if(iarIntegers != null)
+            {
+                newheapuse -= iarIntegers.Length * HeapTrackerObject.HT_INT;
+                iarIntegers = null;
+            }
+            if(iarLists != null)
+            {
+                foreach(LSL_List lis in iarLists)
+                    newheapuse -= HeapTrackerList.Size(lis);
+                iarLists = null;
+            }
+            if(iarObjects != null)
+            {
+                foreach(object obj in iarObjects)
+                    newheapuse -= HeapTrackerObject.Size(obj);
+                iarObjects = null;
+            }
+            if(iarRotations != null)
+            {
+                newheapuse -= iarRotations.Length * HeapTrackerObject.HT_ROT;
+                iarRotations = null;
+            }
+            if(iarStrings != null)
+            {
+                foreach(string str in iarStrings)
+                    newheapuse -= HeapTrackerString.Size(str);
+                iarStrings = null;
+            }
+            if(iarVectors != null)
+            {
+                newheapuse -= iarVectors.Length * HeapTrackerObject.HT_VEC;
+                iarVectors = null;
+            }
+            iarSDTClObjs = null;
+            if(iarSDTIntfObjs != null)
+            {
+                newheapuse -= iarSDTIntfObjs.Length * HeapTrackerObject.HT_DELE;
+                iarSDTIntfObjs = null;
+            }
+
+            heapUse = instance.UpdateHeapUse(heapUse, newheapuse);
+        }
+    }
+
+    public class XMRInstArSizes
+    {
+        public int iasArrays;
+        public int iasChars;
+        public int iasFloats;
+        public int iasIntegers;
+        public int iasLists;
+        public int iasObjects;
+        public int iasRotations;
+        public int iasStrings;
+        public int iasVectors;
+        public int iasSDTClObjs;
+        public int iasSDTIntfObjs;
+
+        public void WriteAsmFile(TextWriter asmFileWriter, string label)
+        {
+            asmFileWriter.WriteLine("  {0}Arrays       {1}", label, iasArrays);
+            asmFileWriter.WriteLine("  {0}Chars        {1}", label, iasChars);
+            asmFileWriter.WriteLine("  {0}Floats       {1}", label, iasFloats);
+            asmFileWriter.WriteLine("  {0}Integers     {1}", label, iasIntegers);
+            asmFileWriter.WriteLine("  {0}Lists        {1}", label, iasLists);
+            asmFileWriter.WriteLine("  {0}Objects      {1}", label, iasObjects);
+            asmFileWriter.WriteLine("  {0}Rotations    {1}", label, iasRotations);
+            asmFileWriter.WriteLine("  {0}Strings      {1}", label, iasStrings);
+            asmFileWriter.WriteLine("  {0}Vectors      {1}", label, iasVectors);
+            asmFileWriter.WriteLine("  {0}SDTClObjs    {1}", label, iasSDTClObjs);
+            asmFileWriter.WriteLine("  {0}SDTIntfObjs  {1}", label, iasSDTIntfObjs);
+        }
+
+        public void WriteToFile(BinaryWriter objFileWriter)
+        {
+            objFileWriter.Write(iasArrays);
+            objFileWriter.Write(iasChars);
+            objFileWriter.Write(iasFloats);
+            objFileWriter.Write(iasIntegers);
+            objFileWriter.Write(iasLists);
+            objFileWriter.Write(iasObjects);
+            objFileWriter.Write(iasRotations);
+            objFileWriter.Write(iasStrings);
+            objFileWriter.Write(iasVectors);
+            objFileWriter.Write(iasSDTClObjs);
+            objFileWriter.Write(iasSDTIntfObjs);
+        }
+
+        public void ReadFromFile(BinaryReader objFileReader)
+        {
+            iasArrays = objFileReader.ReadInt32();
+            iasChars = objFileReader.ReadInt32();
+            iasFloats = objFileReader.ReadInt32();
+            iasIntegers = objFileReader.ReadInt32();
+            iasLists = objFileReader.ReadInt32();
+            iasObjects = objFileReader.ReadInt32();
+            iasRotations = objFileReader.ReadInt32();
+            iasStrings = objFileReader.ReadInt32();
+            iasVectors = objFileReader.ReadInt32();
+            iasSDTClObjs = objFileReader.ReadInt32();
+            iasSDTIntfObjs = objFileReader.ReadInt32();
+        }
+    }
+
+    public class XMRStackFrame
+    {
+        public XMRStackFrame nextSF;
+        public string funcName;
+        public int callNo;
+        public object[] objArray;
+    }
+
+    /*
+     * Contains only items required by the stand-alone compiler
+     * so the compiler doesn't need to pull in all of OpenSim.
+     *
+     * Inherit from ScriptBaseClass so we can be used as 'this'
+     * parameter for backend-API calls, eg llSay().
+     */
+    public abstract class XMRInstAbstract: ScriptBaseClass
+    {
+        public const int CallMode_NORMAL = 0;  // when function is called, it proceeds normally
+        public const int CallMode_SAVE = 1;  // StackSaveException() was thrown, push args/locals to stackFrames
+        public const int CallMode_RESTORE = 2;  // when function is called, it pops state from stackFrames
+
+        public bool suspendOnCheckRunHold;  // suspend script execution until explicitly set false
+        public bool suspendOnCheckRunTemp;  // suspend script execution for single step only
+        public int stackLimit;              // stack must have at least this many bytes free on entry to functions
+        public int m_StackLeft;             // total number of stack bytes yet to be used (init to stacksize)
+
+        public ScriptObjCode m_ObjCode;     // script object code this instance was created from
+
+        public object[] ehArgs;             // event handler argument array
+        public bool doGblInit = true;       // default state_entry() needs to initialize global variables
+        public int stateCode = 0;           // state the script is in (0 = 'default')
+        public int newStateCode = -1;       // if >= 0, in the middle of exiting 'stateCode' and entering 'newStateCode'
+        public ScriptEventCode eventCode = ScriptEventCode.None;
+        // what event handler is executing (or None if not)
+
+        public int callMode = CallMode_NORMAL;
+        // to capture stack frames on stackFrames:
+        //    set to CallMode_SAVE just before throwing StackSaveException()
+        //    from within CheckRun() and cleared to CallMode_NORMAL when
+        //    the exception is caught
+        // to restore stack frames from stackFrames:
+        //    set to CallMode_RESTORE just before calling CallSEH() and 
+        //    cleared to CallMode_NORMAL by CheckRun()
+        public XMRStackFrame stackFrames;   // stack frames being saved/restored
+
+        private static readonly char[] justacomma = { ',' };
+
+        /*
+         * These arrays hold the global variable values for the script instance.
+         * The array lengths are determined by the script compilation,
+         * and are found in ScriptObjCode.glblSizes.
+         */
+        public XMRInstArrays glblVars;
+
+        public XMRInstAbstract()
+        {
+            glblVars = new XMRInstArrays(this);
+        }
+
+        /****************************************************************\
+         *  Abstract function prototypes.                               *
+         *  These functions require access to the OpenSim environment.  *
+        \****************************************************************/
+
+        public abstract void CheckRunWork();
+        public abstract void StateChange();
+
+        [xmrMethodCallsCheckRunAttribute] // calls CheckRun()
+        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
+        public abstract LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
+                                                  int backgroundMask1, int backgroundMask2);
+
+        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
+        public abstract void xmrEventEnqueue(LSL_List ev);
+
+        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
+        public abstract LSL_List xmrEventSaveDets();
+
+        [xmrMethodIsNoisyAttribute]       // calls Stub<somethingorother>()
+        public abstract void xmrEventLoadDets(LSL_List dpList);
+
+
+        /**************************************************\
+         *  Functions what don't require runtime support  *
+         *  beyond what the compiler provides.            *
+        \**************************************************/
+
+        protected int heapLimit;
+        private int heapUsed;
+
+        public virtual int UpdateHeapUse(int olduse, int newuse)
+        {
+            if(newuse <= olduse)
+                Interlocked.Add(ref heapUsed, newuse - olduse);
+            else
+            {
+                int newtotal, oldtotal;
+                do
+                {
+                    oldtotal = Interlocked.Add(ref heapUsed, 0);
+                    newtotal = oldtotal + newuse - olduse;
+                    if(newtotal > heapLimit)
+                    {
+                        //                        System.GC.Collect ();
+                        //                        System.GC.WaitForPendingFinalizers ();
+                        oldtotal = Interlocked.Add(ref heapUsed, 0);
+                        newtotal = oldtotal + newuse - olduse;
+                        if(newtotal > heapLimit)
+                            throw new OutOfHeapException(oldtotal, newtotal, heapLimit);
+                    }
+                } while(Interlocked.CompareExchange(ref heapUsed, newtotal, oldtotal) != oldtotal);
+            }
+
+            return newuse;
+        }
+
+        public int xmrHeapLeft()
+        {
+            return heapLimit - heapUsed;
+        }
+
+        public int xmrHeapUsed()
+        {
+            return heapUsed;
+        }
+
+        /**
+         * @brief Call script's event handler function from the very beginning.
+         * @param instance.stateCode = which state the event is happening in
+         * @param instance.eventCode = which event is happening in that state
+         * @returns when event handler has completed or throws an exception
+         *          with instance.eventCode = ScriptEventCode.None
+         */
+        public void CallSEH()
+        {
+            ScriptEventHandler seh;
+
+            /*
+             * CallMode_NORMAL:  run event handler from the beginning normally
+             * CallMode_RESTORE: restore event handler stack from stackFrames
+             */
+            callMode = (stackFrames == null) ? XMRInstAbstract.CallMode_NORMAL :
+                                               XMRInstAbstract.CallMode_RESTORE;
+
+            while(true)
+            {
+                if(this.newStateCode < 0)
+                {
+                    // Process event given by 'stateCode' and 'eventCode'.
+                    // The event handler should call CheckRun() as often as convenient.
+                    int newState = this.stateCode;
+                    seh = this.m_ObjCode.scriptEventHandlerTable[newState, (int)this.eventCode];
+                    if(seh != null)
+                    {
+                        try
+                        {
+                            seh(this);
+                        }
+                        catch(ScriptChangeStateException scse)
+                        {
+                            newState = scse.newState;
+                        }
+                    }
+                    this.ehArgs = null;  // we are done with them and no args for
+                                         // exit_state()/enter_state() anyway
+
+                    // The usual case is no state change.
+                    // Even a 'state <samestate>;' statement has no effect except to exit out.
+                    // It does not execute the state_exit() or state_entry() handlers.
+                    // See http://wiki.secondlife.com/wiki/State
+                    if(newState == this.stateCode)
+                        break;
+
+                    // Save new state in a more permanent location in case we
+                    // get serialized out while in the state_exit() handler.
+                    this.newStateCode = newState;
+                }
+
+                // Call old state's state_exit() handler.
+                this.eventCode = ScriptEventCode.state_exit;
+                seh = this.m_ObjCode.scriptEventHandlerTable[this.stateCode, (int)ScriptEventCode.state_exit];
+                if(seh != null)
+                {
+                    try
+                    {
+                        seh(this);
+                    }
+                    catch(ScriptChangeStateException scse)
+                    {
+                        this.newStateCode = scse.newState;
+                    }
+                }
+
+                // Switch over to the new state's state_entry() handler.
+                this.stateCode = this.newStateCode;
+                this.eventCode = ScriptEventCode.state_entry;
+                this.newStateCode = -1;
+
+                // Now that the old state can't possibly start any more activity,
+                // cancel any listening handlers, etc, of the old state.
+                this.StateChange();
+
+                // Loop back to execute new state's state_entry() handler.
+            }
+
+            // Event no longer being processed.
+            this.eventCode = ScriptEventCode.None;
+        }
+
+        /**
+         * @brief For compatibility with old code.
+         */
+        public void CheckRun(int line)
+        {
+            CheckRunStack();
+        }
+
+        /**
+         * @brief Called at beginning of complex functions to see if they
+         *        are nested too deep possibly in a recursive loop.
+         */
+        public void CheckRunStack()
+        {
+            if(m_StackLeft < stackLimit)
+                throw new OutOfStackException();
+
+            CheckRunQuick();
+        }
+
+        /**
+         * @brief Called in each iteration of a loop to see if running too long.
+         */
+        public void CheckRunQuick()
+        {
+            //            if (suspendOnCheckRunHold || suspendOnCheckRunTemp)
+            CheckRunWork();
+        }
+
+        /**
+         * @brief Called during CallMode_SAVE to create a stackframe save object that saves 
+         *        local variables and calling point within the function.
+         * @param funcName = name of function whose frame is being saved
+         * @param callNo = call number (ie, return address) within function to restart at
+         * @param nSaves = number of variables the function will save
+         * @returns an object[nSaves] where function can save variables
+         */
+        public object[] CaptureStackFrame(string funcName, int callNo, int nSaves)
+        {
+            XMRStackFrame sf = new XMRStackFrame();
+            sf.nextSF = stackFrames;
+            sf.funcName = funcName;
+            sf.callNo = callNo;
+            sf.objArray = new object[nSaves];
+            stackFrames = sf;
+            return sf.objArray;
+        }
+
+        /**
+         * @brief Called during CallMode_RESTORE to pop a stackframe object to restore 
+         *        local variables and calling point within the function.
+         * @param funcName = name of function whose frame is being restored
+         * @returns the object[nSaves] where function can retrieve variables
+         *          callNo = as passed to CaptureStackFrame() indicating restart point
+         */
+        public object[] RestoreStackFrame(string funcName, out int callNo)
+        {
+            XMRStackFrame sf = stackFrames;
+            if(sf.funcName != funcName)
+                throw new Exception("frame mismatch " + sf.funcName + " vs " + funcName);
+
+            callNo = sf.callNo;
+            stackFrames = sf.nextSF;
+            return sf.objArray;
+        }
+
+        /**
+         * @brief Convert all LSL_Integers in a list to System.Int32s, 
+         *        as required by llParcelMediaQuery().
+         */
+        public static LSL_List FixLLParcelMediaQuery(LSL_List oldlist)
+        {
+            object[] oldarray = oldlist.Data;
+            int len = oldarray.Length;
+            object[] newarray = new object[len];
+            for(int i = 0; i < len; i++)
+            {
+                object obj = oldarray[i];
+                if(obj is LSL_Integer)
+                    obj = (int)(LSL_Integer)obj;
+                newarray[i] = obj;
+            }
+            return new LSL_List(newarray);
+        }
+
+        /**
+         * @brief Convert *SOME* LSL_Integers in a list to System.Int32s, 
+         *        as required by llParcelMediaCommandList().
+         */
+        public static LSL_List FixLLParcelMediaCommandList(LSL_List oldlist)
+        {
+            object[] oldarray = oldlist.Data;
+            int len = oldarray.Length;
+            object[] newarray = new object[len];
+            int verbatim = 0;
+            for(int i = 0; i < len; i++)
+            {
+                object obj = oldarray[i];
+                if(--verbatim < 0)
+                {
+                    if(obj is LSL_Integer)
+                        obj = (int)(LSL_Integer)obj;
+                    if(obj is int)
+                    {
+                        switch((int)obj)
+                        {
+                            case ScriptBaseClass.PARCEL_MEDIA_COMMAND_AUTO_ALIGN:
+                                // leave next integer as LSL_Integer
+                                verbatim = 1;
+                                break;
+
+                            case ScriptBaseClass.PARCEL_MEDIA_COMMAND_SIZE:
+                                // leave next two integers as LSL_Integer
+                                verbatim = 2;
+                                break;
+
+                        }
+                    }
+                }
+                newarray[i] = obj;
+            }
+            return new LSL_List(newarray);
+        }
+
+        public static int xmrHashCode(int i)
+        {
+            return i.GetHashCode();
+        }
+
+        public static int xmrHashCode(double f)
+        {
+            return f.GetHashCode();
+        }
+
+        public static int xmrHashCode(object o)
+        {
+            return o.GetHashCode();
+        }
+
+        public static int xmrHashCode(string s)
+        {
+            return s.GetHashCode();
+        }
+
+        public string xmrTypeName(object o)
+        {
+            /*
+             * Basic types return constant strings of the script-visible type name.
+             */
+            if(o is XMR_Array)
+                return "array";
+            if(o is bool)
+                return "bool";
+            if(o is char)
+                return "char";
+            if(o is Exception)
+                return "exception";
+            if(o is double)
+                return "float";
+            if(o is float)
+                return "float";
+            if(o is LSL_Float)
+                return "float";
+            if(o is int)
+                return "integer";
+            if(o is LSL_Integer)
+                return "integer";
+            if(o is LSL_List)
+                return "list";
+            if(o is LSL_Rotation)
+                return "rotation";
+            if(o is LSL_String)
+                return "string";
+            if(o is string)
+                return "string";
+            if(o is LSL_Vector)
+                return "vector";
+
+            /*
+             * A script-defined interface is represented as an array of delegates.
+             * If that is the case, convert it to the object of the script-defined 
+             * class that is implementing the interface.  This should let the next 
+             * step get the script-defined type name of the object.
+             */
+            if(o is Delegate[])
+                o = ((Delegate[])o)[0].Target;
+
+            /*
+             * If script-defined class instance, get the script-defined 
+             * type name.
+             */
+            if(o is XMRSDTypeClObj)
+                return ((XMRSDTypeClObj)o).sdtcClass.longName.val;
+
+            /*
+             * If it's a delegate, maybe we can look up its script-defined type name.
+             */
+            Type ot = o.GetType();
+            if(o is Delegate)
+            {
+                String os;
+                if(m_ObjCode.sdDelTypes.TryGetValue(ot, out os))
+                    return os;
+            }
+
+            /*
+             * Don't know what it is, get the C#-level type name.
+             */
+            return ot.ToString();
+        }
+
+        /**
+         * @brief Call the current state's event handler.
+         * @param ev = as returned by xmrEventDequeue saying which event handler to call
+         *             and what argument list to pass to it.  The llDetect...() parameters
+         *             are as currently set for the script (use xmrEventLoadDets to set how
+         *             you want them to be different).
+         */
+        public void xmrEventCallHandler(LSL_List ev)
+        {
+            object[] data = ev.Data;
+            int evc = (int)(ev.GetLSLIntegerItem(0).value & 0xFFFFFFFF);
+            ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc];
+            if(seh != null)
+            {
+                int nargs = data.Length - 1;
+                object[] args = new object[nargs];
+                Array.Copy(data, 1, args, 0, nargs);
+
+                object[] saveEHArgs = this.ehArgs;
+                ScriptEventCode saveEventCode = this.eventCode;
+
+                this.ehArgs = args;
+                this.eventCode = (ScriptEventCode)evc;
+
+                seh(this);
+
+                this.ehArgs = saveEHArgs;
+                this.eventCode = saveEventCode;
+            }
+        }
+
+        /**
+         * @brief Sane substring functions.
+         */
+        public string xmrSubstring(string s, int offset)
+        {
+            if(offset >= s.Length)
+                return "";
+            return s.Substring(offset);
+        }
+
+        // C# style
+        public string xmrSubstring(string s, int offset, int length)
+        {
+            if(length <= 0)
+                return "";
+            if(offset >= s.Length)
+                return "";
+            if(length > s.Length - offset)
+                length = s.Length - offset;
+            return s.Substring(offset, length);
+        }
+
+        // java style
+        public string xmrJSubstring(string s, int beg, int end)
+        {
+            if(end <= beg)
+                return "";
+            if(beg >= s.Length)
+                return "";
+            if(end > s.Length)
+                end = s.Length;
+            return s.Substring(beg, end - beg);
+        }
+
+        /**
+         * @brief String begins and ends with test.
+         */
+        public bool xmrStringStartsWith(string s, string t)
+        {
+            return s.StartsWith(t);
+        }
+
+        public bool xmrStringEndsWith(string s, string t)
+        {
+            return s.EndsWith(t);
+        }
+
+        /**
+         * @brief [Last]IndexOf with starting position (just like C#)
+         */
+        public int xmrStringIndexOf(string haystack, string needle)
+        {
+            return haystack.IndexOf(needle);
+        }
+
+        public int xmrStringIndexOf(string haystack, string needle, int startat)
+        {
+            return haystack.IndexOf(needle, startat);
+        }
+
+        public int xmrStringLastIndexOf(string haystack, string needle)
+        {
+            return haystack.LastIndexOf(needle);
+        }
+
+        public int xmrStringLastIndexOf(string haystack, string needle, int startat)
+        {
+            return haystack.LastIndexOf(needle, startat);
+        }
+
+        /**
+         * @brief These conversions throw exceptions if there is anything stinky...
+         */
+        public double xmrString2Float(string s)
+        {
+            return double.Parse(s, CultureInfo.InvariantCulture);
+        }
+
+        public int xmrString2Integer(string s)
+        {
+            s = s.Trim();
+            if(s.StartsWith("0x") || s.StartsWith("0X"))
+                return int.Parse(s.Substring(2), NumberStyles.HexNumber);
+
+            return int.Parse(s, CultureInfo.InvariantCulture);
+        }
+
+        public LSL_Rotation xmrString2Rotation(string s)
+        {
+            s = s.Trim();
+            if(!s.StartsWith("<") || !s.EndsWith(">"))
+                throw new FormatException("doesn't begin with < and end with >");
+
+            s = s.Substring(1, s.Length - 2);
+            string[] splitup = s.Split(justacomma, 5);
+            if(splitup.Length != 4)
+                throw new FormatException("doesn't have exactly 3 commas");
+
+            double x = double.Parse(splitup[0], CultureInfo.InvariantCulture);
+            double y = double.Parse(splitup[1], CultureInfo.InvariantCulture);
+            double z = double.Parse(splitup[2], CultureInfo.InvariantCulture);
+            double w = double.Parse(splitup[3], CultureInfo.InvariantCulture);
+            return new LSL_Rotation(x, y, z, w);
+        }
+
+        public LSL_Vector xmrString2Vector(string s)
+        {
+            s = s.Trim();
+            if(!s.StartsWith("<") || !s.EndsWith(">"))
+                throw new FormatException("doesn't begin with < and end with >");
+
+            s = s.Substring(1, s.Length - 2);
+            string[] splitup = s.Split(justacomma, 4);
+            if(splitup.Length != 3)
+                throw new FormatException("doesn't have exactly 2 commas");
+
+            double x = double.Parse(splitup[0], CultureInfo.InvariantCulture);
+            double y = double.Parse(splitup[1], CultureInfo.InvariantCulture);
+            double z = double.Parse(splitup[2], CultureInfo.InvariantCulture);
+            return new LSL_Vector(x, y, z);
+        }
+
+        /**
+         * @brief Access C#-style formatted numeric conversions.
+         */
+        public string xmrFloat2String(double val, string fmt)
+        {
+            return val.ToString(fmt, CultureInfo.InvariantCulture);
+        }
+
+        public string xmrInteger2String(int val, string fmt)
+        {
+            return val.ToString(fmt, CultureInfo.InvariantCulture);
+        }
+
+        public string xmrRotation2String(LSL_Rotation val, string fmt)
+        {
+            return "<" + val.x.ToString(fmt, CultureInfo.InvariantCulture) + "," +
+                         val.y.ToString(fmt, CultureInfo.InvariantCulture) + "," +
+                         val.z.ToString(fmt, CultureInfo.InvariantCulture) + "," +
+                         val.s.ToString(fmt, CultureInfo.InvariantCulture) + ">";
+        }
+
+        public string xmrVector2String(LSL_Vector val, string fmt)
+        {
+            return "<" + val.x.ToString(fmt, CultureInfo.InvariantCulture) + "," +
+                         val.y.ToString(fmt, CultureInfo.InvariantCulture) + "," +
+                         val.z.ToString(fmt, CultureInfo.InvariantCulture) + ">";
+        }
+
+        /**
+         * @brief Get a delegate for a script-defined function.
+         * @param name = name of the function including arg types, eg,
+         *               "Verify(array,list,string)"
+         * @param sig  = script-defined type name
+         * @param targ = function's 'this' pointer or null if static
+         * @returns delegate for the script-defined function
+         */
+        public Delegate GetScriptMethodDelegate(string name, string sig, object targ)
+        {
+            DynamicMethod dm = m_ObjCode.dynamicMethods[name];
+            TokenDeclSDTypeDelegate dt = (TokenDeclSDTypeDelegate)m_ObjCode.sdObjTypesName[sig];
+            return dm.CreateDelegate(dt.GetSysType(), targ);
+        }
+
+        /**
+         * @brief Try to cast the thrown object to the given script-defined type.
+         * @param thrown = what object was thrown
+         * @param inst = what script instance we are running in
+         * @param sdtypeindex = script-defined type to try to cast it to
+         * @returns null: thrown is not castable to sdtypename
+         *          else: an object casted to sdtypename
+         */
+        public static object XMRSDTypeCatchTryCastToSDType(object thrown, XMRInstAbstract inst, int sdtypeindex)
+        {
+            TokenDeclSDType sdType = inst.m_ObjCode.sdObjTypesIndx[sdtypeindex];
+
+            /*
+             * If it is a script-defined interface object, convert to the original XMRSDTypeClObj.
+             */
+            if(thrown is Delegate[])
+            {
+                thrown = ((Delegate[])thrown)[0].Target;
+            }
+
+            /*
+             * If it is a script-defined delegate object, make sure it is an instance of the expected type.
+             */
+            if(thrown is Delegate)
+            {
+                Type ot = thrown.GetType();
+                Type tt = sdType.GetSysType();
+                return (ot == tt) ? thrown : null;
+            }
+
+            /*
+             * If it is a script-defined class object, make sure it is an instance of the expected class.
+             */
+            if(thrown is XMRSDTypeClObj)
+            {
+
+                /*
+                 * Step from the object's actual class rootward.
+                 * If we find the requested class along the way, the cast is valid.
+                 * If we run off the end of the root, the cast is not valid.
+                 */
+                for(TokenDeclSDTypeClass ac = ((XMRSDTypeClObj)thrown).sdtcClass; ac != null; ac = ac.extends)
+                {
+                    if(ac == sdType)
+                        return thrown;
+                }
+            }
+
+            /*
+             * Don't know what it is, assume it is not what caller wants.
+             */
+            return null;
+        }
+
+        /**
+         * @brief Allocate and access fixed-dimension arrays.
+         */
+        public static object xmrFixedArrayAllocC(int len)
+        {
+            return new char[len];
+        }
+        public static object xmrFixedArrayAllocF(int len)
+        {
+            return new double[len];
+        }
+        public static object xmrFixedArrayAllocI(int len)
+        {
+            return new int[len];
+        }
+        public static object xmrFixedArrayAllocO(int len)
+        {
+            return new object[len];
+        }
+
+        public static char xmrFixedArrayGetC(object arr, int idx)
+        {
+            return ((char[])arr)[idx];
+        }
+        public static double xmrFixedArrayGetF(object arr, int idx)
+        {
+            return ((double[])arr)[idx];
+        }
+        public static int xmrFixedArrayGetI(object arr, int idx)
+        {
+            return ((int[])arr)[idx];
+        }
+        public static object xmrFixedArrayGetO(object arr, int idx)
+        {
+            return ((object[])arr)[idx];
+        }
+
+        public static void xmrFixedArraySetC(object arr, int idx, char val)
+        {
+            ((char[])arr)[idx] = val;
+        }
+        public static void xmrFixedArraySetF(object arr, int idx, double val)
+        {
+            ((double[])arr)[idx] = val;
+        }
+        public static void xmrFixedArraySetI(object arr, int idx, int val)
+        {
+            ((int[])arr)[idx] = val;
+        }
+        public static void xmrFixedArraySetO(object arr, int idx, object val)
+        {
+            ((object[])arr)[idx] = val;
+        }
+
+        /**
+         * @brief Copy from one script-defined array to another.
+         * @param srcobj = source script-defined array class object pointer
+         * @param srcstart = offset in source array to start copying from
+         * @param dstobj = destination script-defined array class object pointer
+         * @param dststart = offset in destination arry to start copying to
+         * @param count = number of elements to copy
+         */
+        public static void xmrArrayCopy(object srcobj, int srcstart, object dstobj, int dststart, int count)
+        {
+            /*
+             * The script writer should only pass us script-defined class objects.
+             * Throw exception otherwise.
+             */
+            XMRSDTypeClObj srcsdt = (XMRSDTypeClObj)srcobj;
+            XMRSDTypeClObj dstsdt = (XMRSDTypeClObj)dstobj;
+
+            /*
+             * Get the script-visible type name of the arrays, brackets and all.
+             */
+            string srctypename = srcsdt.sdtcClass.longName.val;
+            string dsttypename = dstsdt.sdtcClass.longName.val;
+
+            /*
+             * The part before the first '[' of each should match exactly,
+             * meaning the basic data type (eg, float, List<string>) is the same.
+             * And there must be a '[' in each meaning that it is a script-defined array type.
+             */
+            int i = srctypename.IndexOf('[');
+            int j = dsttypename.IndexOf('[');
+            if((i < 0) || (j < 0))
+                throw new InvalidCastException("non-array passed: " + srctypename + " and/or " + dsttypename);
+            if((i != j) || !srctypename.StartsWith(dsttypename.Substring(0, j)))
+                throw new ArrayTypeMismatchException(srctypename + " vs " + dsttypename);
+
+            /*
+             * The number of brackets must match exactly.
+             * This permits copying from something like a float[,][] to something like a float[][].
+             * But you cannot copy from a float[][] to a float[] or wisa wersa.
+             * Counting either '[' or ']' would work equally well.
+             */
+            int srclen = srctypename.Length;
+            int dstlen = dsttypename.Length;
+            int srcjags = 0;
+            int dstjags = 0;
+            while(++i < srclen)
+                if(srctypename[i] == ']')
+                    srcjags++;
+            while(++j < dstlen)
+                if(dsttypename[j] == ']')
+                    dstjags++;
+            if(dstjags != srcjags)
+                throw new ArrayTypeMismatchException(srctypename + " vs " + dsttypename);
+
+            /*
+             * Perform the copy.
+             */
+            Array srcarray = (Array)srcsdt.instVars.iarObjects[0];
+            Array dstarray = (Array)dstsdt.instVars.iarObjects[0];
+            Array.Copy(srcarray, srcstart, dstarray, dststart, count);
+        }
+
+        /**
+         * @brief Copy from an array to a list.
+         * @param srcar = the array to copy from
+         * @param start = where to start in the array
+         * @param count = number of elements
+         * @returns the list
+         */
+        public static LSL_List xmrArray2List(object srcar, int start, int count)
+        {
+            /*
+             * Get the script-visible type of the array.
+             * We only do arrays.
+             */
+            XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
+            TokenDeclSDTypeClass sdtClass = array.sdtcClass;
+            if(sdtClass.arrayOfRank == 0)
+                throw new InvalidCastException("only do arrays not " + sdtClass.longName.val);
+
+            /*
+             * Validate objects they want to put in the list.
+             * We can't allow anything funky that OpenSim runtime doesn't expect.
+             */
+            Array srcarray = (Array)array.instVars.iarObjects[0];
+            object[] output = new object[count];
+            for(int i = 0; i < count; i++)
+            {
+                object src = srcarray.GetValue(i + start);
+                if(src == null)
+                    throw new NullReferenceException("null element " + i);
+                if(src is double)
+                {
+                    output[i] = new LSL_Float((double)src);
+                    continue;
+                }
+                if(src is int)
+                {
+                    output[i] = new LSL_Integer((int)src);
+                    continue;
+                }
+                if(src is LSL_Rotation)
+                {
+                    output[i] = src;
+                    continue;
+                }
+                if(src is LSL_Vector)
+                {
+                    output[i] = src;
+                    continue;
+                }
+                if(src is string)
+                {
+                    output[i] = new LSL_String((string)src);
+                    continue;
+                }
+                throw new InvalidCastException("invalid element " + i + " type " + src.GetType().Name);
+            }
+
+            /*
+             * Make a list out of that now immutable array.
+             */
+            return new LSL_List(output);
+        }
+
+        /**
+         * @brief Copy from a list to an array.
+         * @param srclist  = list to copy from
+         * @param srcstart = where to start in the list
+         * @param dstobj   = array to copy to
+         * @param dststart = where to start in the array
+         * @param count    = number of elements
+         */
+        public static void xmrList2Array(LSL_List srclist, int srcstart, object dstobj, int dststart, int count)
+        {
+            /*
+             * Get the script-visible type of the destination.
+             * We only do arrays.
+             */
+            XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
+            TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
+            if(sdtClass.arrayOfType == null)
+                throw new InvalidCastException("only do arrays not " + sdtClass.longName.val);
+
+            /*
+             * Copy from the immutable array to the mutable array.
+             * Strip off any LSL wrappers as the script code doesn't expect any.
+             */
+            object[] srcarr = srclist.Data;
+            Array dstarr = (Array)dstarray.instVars.iarObjects[0];
+
+            for(int i = 0; i < count; i++)
+            {
+                object obj = srcarr[i + srcstart];
+                if(obj is LSL_Float)
+                    obj = ((LSL_Float)obj).value;
+                else if(obj is LSL_Integer)
+                    obj = ((LSL_Integer)obj).value;
+                else if(obj is LSL_String)
+                    obj = ((LSL_String)obj).m_string;
+                dstarr.SetValue(obj, i + dststart);
+            }
+        }
+
+        /**
+         * @brief Copy from an array of characters to a string.
+         * @param srcar = the array to copy from
+         * @param start = where to start in the array
+         * @param count = number of elements
+         * @returns the string
+         */
+        public static string xmrChars2String(object srcar, int start, int count)
+        {
+            /*
+             * Make sure they gave us a script-defined array object.
+             */
+            XMRSDTypeClObj array = (XMRSDTypeClObj)srcar;
+            TokenDeclSDTypeClass sdtClass = array.sdtcClass;
+            if(sdtClass.arrayOfRank == 0)
+                throw new InvalidCastException("only do arrays not " + sdtClass.longName.val);
+
+            /*
+             * We get a type cast error from mono if they didn't give us a character array.
+             * But if it is ok, create a string from the requested characters.
+             */
+            char[] srcarray = (char[])array.instVars.iarObjects[0];
+            return new string(srcarray, start, count);
+        }
+
+        /**
+         * @brief Copy from a string to a character array.
+         * @param srcstr   = string to copy from
+         * @param srcstart = where to start in the string
+         * @param dstobj   = array to copy to
+         * @param dststart = where to start in the array
+         * @param count    = number of elements
+         */
+        public static void xmrString2Chars(string srcstr, int srcstart, object dstobj, int dststart, int count)
+        {
+            /*
+             * Make sure they gave us a script-defined array object.
+             */
+            XMRSDTypeClObj dstarray = (XMRSDTypeClObj)dstobj;
+            TokenDeclSDTypeClass sdtClass = dstarray.sdtcClass;
+            if(sdtClass.arrayOfType == null)
+                throw new InvalidCastException("only do arrays not " + sdtClass.longName.val);
+
+            /*
+             * We get a type cast error from mono if they didn't give us a character array.
+             * But if it is ok, copy from the string to the character array.
+             */
+            char[] dstarr = (char[])dstarray.instVars.iarObjects[0];
+            for(int i = 0; i < count; i++)
+                dstarr[i + dststart] = srcstr[i + srcstart];
+        }
+
+        /**
+         * @brief Implement osParseJSON() so we return an array to the script.
+         *        No coherent example of its use in scripts on web found.
+         * see http://www.json.org/ for more details on JSON
+         */
+        private static LSL_List nullList = new LSL_List(new object[0]);
+        public new XMR_Array osParseJSON(string json)
+        {
+            XMR_Array dict = new XMR_Array(this);
+            int idx = ParseJSON(dict, nullList, json, 0);
+            while(idx < json.Length)
+            {
+                if(json[idx] > ' ')
+                    throw new Exception("left-over json " + json);
+                idx++;
+            }
+            return dict;
+        }
+
+        private static int ParseJSON(XMR_Array dict, LSL_List keys, string json, int idx)
+        {
+            char c;
+
+            while((c = json[idx++]) <= ' ')
+            {
+            }
+            switch(c)
+            {
+
+                // '{' <keystring> ':' <value> [ ',' <keystring> ':' <value> ... ] '}'
+                case '{':
+                    do
+                    {
+                        string key = ParseJSONString(json, ref idx);
+                        while((c = json[idx++]) <= ' ')
+                        {
+                        }
+                        if(c != ':')
+                            throw new Exception("missing : after key");
+                        idx = ParseJSON(dict, ParseJSONKeyAdd(keys, key), json, idx);
+                        while((c = json[idx++]) <= ' ')
+                        {
+                        }
+                    } while(c == ',');
+                    if(c != '}')
+                        throw new Exception("missing , or } after value");
+                    break;
+
+
+                // '[' <value> [ ',' <value> ... ] ']'
+                case '[':
+                    int index = 0;
+                    do
+                    {
+                        object key = index++;
+                        idx = ParseJSON(dict, ParseJSONKeyAdd(keys, key), json, idx);
+                        while((c = json[idx++]) <= ' ')
+                        {
+                        }
+                    } while(c == ',');
+                    if(c != ']')
+                        throw new Exception("missing , or ] after value");
+                    break;
+
+
+                // '"'<string>'"'
+                case '"':
+                    {
+                        --idx;
+                        string val = ParseJSONString(json, ref idx);
+                        dict.SetByKey(keys, val);
+                        break;
+                    }
+                // true false null
+                case 't':
+                    if(json.Substring(idx, 3) != "rue")
+                        throw new Exception("bad true in json");
+                    idx += 3;
+                    dict.SetByKey(keys, 1);
+                    break;
+
+                case 'f':
+                    if(json.Substring(idx, 4) != "alse")
+                        throw new Exception("bad false in json");
+                    idx += 4;
+                    dict.SetByKey(keys, 0);
+                    break;
+
+                case 'n':
+                    if(json.Substring(idx, 3) != "ull")
+                        throw new Exception("bad null in json");
+                    idx += 3;
+                    dict.SetByKey(keys, null);
+                    break;
+
+                // otherwise assume it's a number
+                default:
+                    {
+                        --idx;
+                        object val = ParseJSONNumber(json, ref idx);
+                        dict.SetByKey(keys, val);
+                        break;
+                    }
+            }
+            return idx;
+        }
+
+        // Given the key for a whole array, create a key for a given element of the array
+        private static LSL_List ParseJSONKeyAdd(LSL_List oldkeys, object key)
+        {
+            int oldkeyslen = oldkeys.Length;
+            object[] array = oldkeys.Data;
+            Array.Resize<object>(ref array, oldkeyslen + 1);
+            array[oldkeyslen] = key;
+            return new LSL_List(array);
+        }
+
+        // Parse out a JSON string
+        private static string ParseJSONString(string json, ref int idx)
+        {
+            char c;
+
+            while((c = json[idx++]) <= ' ')
+            {
+            }
+            if(c != '"')
+                throw new Exception("bad start of json string");
+
+            StringBuilder sb = new StringBuilder();
+            while((c = json[idx++]) != '"')
+            {
+                if(c == '\\')
+                {
+                    c = json[idx++];
+                    switch(c)
+                    {
+                        case 'b':
+                            c = '\b';
+                            break;
+
+                        case 'f':
+                            c = '\f';
+                            break;
+
+                        case 'n':
+                            c = '\n';
+                            break;
+
+                        case 'r':
+                            c = '\r';
+                            break;
+
+                        case 't':
+                            c = '\t';
+                            break;
+
+                        case 'u':
+                            c = (char)Int32.Parse(json.Substring(idx, 4),
+                                                    System.Globalization.NumberStyles.HexNumber);
+                            idx += 4;
+                            break;
+
+                        default:
+                            break;
+                    }
+                }
+                sb.Append(c);
+            }
+            return sb.ToString();
+        }
+
+        // Parse out a JSON number
+        private static object ParseJSONNumber(string json, ref int idx)
+        {
+            char c;
+
+            while((c = json[idx++]) <= ' ')
+            {
+            }
+
+            bool expneg = false;
+            bool isneg = false;
+            int decpt = -1;
+            int expon = 0;
+            int ival = 0;
+            double dval = 0;
+
+            if(c == '-')
+            {
+                isneg = true;
+                c = json[idx++];
+            }
+            if((c < '0') || (c > '9'))
+                throw new Exception("bad json number");
+
+            while((c >= '0') && (c <= '9'))
+            {
+                dval *= 10;
+                ival *= 10;
+                dval += c - '0';
+                ival += c - '0';
+                c = '\0';
+                if(idx < json.Length)
+                    c = json[idx++];
+            }
+            if(c == '.')
+            {
+                decpt = 0;
+                c = '\0';
+                if(idx < json.Length)
+                    c = json[idx++];
+                while((c >= '0') && (c <= '9'))
+                {
+                    dval *= 10;
+                    dval += c - '0';
+                    decpt++;
+                    c = '\0';
+                    if(idx < json.Length)
+                        c = json[idx++];
+                }
+            }
+            if((c == 'e') || (c == 'E'))
+            {
+                if(decpt < 0)
+                    decpt = 0;
+                c = json[idx++];
+                if(c == '-')
+                    expneg = true;
+                if((c == '-') || (c == '+'))
+                    c = json[idx++];
+                while((c >= '0') && (c <= '9'))
+                {
+                    expon *= 10;
+                    expon += c - '0';
+                    c = '\0';
+                    if(idx < json.Length)
+                        c = json[idx++];
+                }
+                if(expneg)
+                    expon = -expon;
+            }
+
+            if(c != 0)
+                --idx;
+            if(decpt < 0)
+            {
+                if(isneg)
+                    ival = -ival;
+                return ival;
+            }
+            else
+            {
+                if(isneg)
+                    dval = -dval;
+                dval *= Math.Pow(10, expon - decpt);
+                return dval;
+            }
+        }
+
+        /**
+         * @brief Exception-related runtime calls.
+         */
+        // Return exception message (no type information just the message)
+        public static string xmrExceptionMessage(Exception ex)
+        {
+            return ex.Message;
+        }
+
+        // Return stack trace (no type or message, just stack trace lines: at ... \n)
+        public string xmrExceptionStackTrace(Exception ex)
+        {
+            return XMRExceptionStackString(ex);
+        }
+
+        // Return value thrown by a throw statement
+        public static object xmrExceptionThrownValue(Exception ex)
+        {
+            return ((ScriptThrownException)ex).thrown;
+        }
+
+        // Return exception's short type name, eg, NullReferenceException, ScriptThrownException, etc.
+        public static string xmrExceptionTypeName(Exception ex)
+        {
+            return ex.GetType().Name;
+        }
+
+        // internal use only: converts any IL addresses in script-defined methods to source location equivalent
+        // Mono ex.StackTrace:
+        //   at OpenSim.Region.ScriptEngine.YEngine.TypeCast.ObjectToInteger (System.Object x) [0x0005e] in /home/kunta/opensim-0.9/addon-modules/YEngine/Module/MMRScriptTypeCast.cs:750
+        //   at (wrapper dynamic-method) System.Object:default state_entry (OpenSim.Region.ScriptEngine.YEngine.XMRInstAbstract) [0x00196]
+
+        // Microsoft ex.StackTrace:
+        //    at OpenSim.Region.ScriptEngine.YEngine.TypeCast.ObjectToInteger(Object x) in C:\Users\mrieker\opensim-0.9-source\addon-modules\YEngine\Module\MMRScriptTypeCast.cs:line 750
+        //    at default state_entry (XMRInstAbstract )
+        public string XMRExceptionStackString(Exception ex)
+        {
+            string stwhole = ex.StackTrace;
+            string[] stlines = stwhole.Split(new char[] { '\n' });
+            StringBuilder sb = new StringBuilder();
+            foreach(string st in stlines)
+            {
+                string stline = st.Trim();
+                if(stline == "")
+                    continue;
+
+                // strip 'at' off the front of line
+                if(stline.StartsWith("at "))
+                {
+                    stline = stline.Substring(3);
+                }
+
+                // strip '(wrapper ...' off front of line
+                if(stline.StartsWith("(wrapper dynamic-method) System.Object:"))
+                {
+                    stline = stline.Substring(39);
+                }
+
+                // strip the (systemargtypes...) from our dynamic method names cuz it's messy
+                //  'default state_entry (XMRInstAbstract )'
+                //      => 'default state_entry'
+                //  'CallSomethingThatThrows(string) (OpenSim.Region.ScriptEngine.YEngine.XMRInstance,string)'
+                //      => 'CallSomethingThatThrows(string)'
+                int kwin = stline.IndexOf(" in ");
+                int br0x = stline.IndexOf(" [0x");
+                int pastCloseParen = stline.Length;
+                if((kwin >= 0) && (br0x >= 0))
+                    pastCloseParen = Math.Min(kwin, br0x);
+                else if(kwin >= 0)
+                    pastCloseParen = kwin;
+                else if(br0x >= 0)
+                    pastCloseParen = br0x;
+                else
+                    pastCloseParen = stline.Length;
+                int endFuncName = pastCloseParen;
+                while(endFuncName > 0)
+                {
+                    if(stline[--endFuncName] == '(')
+                        break;
+                }
+                while(endFuncName > 0)
+                {
+                    if(stline[endFuncName - 1] != ' ')
+                        break;
+                    --endFuncName;
+                }
+                string funcName = stline.Substring(0, endFuncName);
+                KeyValuePair<int, ScriptSrcLoc>[] srcLocs;
+                if(m_ObjCode.scriptSrcLocss.TryGetValue(funcName, out srcLocs))
+                {
+                    stline = stline.Substring(0, endFuncName) + stline.Substring(pastCloseParen);
+                    kwin = stline.IndexOf(" in ");
+                    br0x = stline.IndexOf(" [0x");
+                }
+
+                // keyword 'in' is just before filename:linenumber that goes to end of line
+                // trim up the corresponding filename (ie, remove useless path info)
+                if(kwin >= 0)
+                {
+                    int begfn = kwin + 4;
+                    int slash = begfn;
+                    for(int i = begfn; i < stline.Length; i++)
+                    {
+                        char c = stline[i];
+                        if((c == '/') || (c == '\\'))
+                            slash = i + 1;
+                    }
+                    stline = stline.Substring(0, begfn) + stline.Substring(slash);
+                }
+                else if(srcLocs != null)
+                {
+
+                    // no filename:linenumber info, try to convert IL offset
+                    if(br0x >= 0)
+                    {
+                        try
+                        {
+                            int begiloffs = br0x + 4;
+                            int endiloffs = stline.IndexOf("]", begiloffs);
+                            int iloffset = int.Parse(stline.Substring(begiloffs, endiloffs - begiloffs),
+                                                       System.Globalization.NumberStyles.HexNumber);
+
+                            int srcLocIdx;
+                            int srcLocLen = srcLocs.Length;
+                            for(srcLocIdx = 0; ++srcLocIdx < srcLocLen;)
+                            {
+                                if(iloffset < srcLocs[srcLocIdx].Key)
+                                    break;
+                            }
+                            ScriptSrcLoc srcLoc = srcLocs[--srcLocIdx].Value;
+
+                            stline = stline.Substring(0, br0x) + " <" +
+                                        srcLoc.file + '(' + srcLoc.line + ',' + srcLoc.posn + ")>";
+                        }
+                        catch
+                        {
+                        }
+                    }
+                }
+
+                // put edited line in output string
+                if(sb.Length > 0)
+                    sb.AppendLine();
+                sb.Append("  at ");
+                sb.Append(stline);
+            }
+            return sb.ToString();
+        }
+
+        /**
+         * @brief List fonts available.
+         */
+        public LSL_List xmrFontsAvailable()
+        {
+            System.Drawing.FontFamily[] families = System.Drawing.FontFamily.Families;
+            object[] output = new object[families.Length];
+            for(int i = 0; i < families.Length; i++)
+                output[i] = new LSL_String(families[i].Name);
+
+            return new LSL_List(output);
+        }
+
+        /************************\
+         *  Used by decompiler  *
+        \************************/
+
+        public bool xmrRotationToBool(LSL_Rotation x)
+        {
+            return TypeCast.RotationToBool(x);
+        }
+        public bool xmrStringToBool(string x)
+        {
+            return TypeCast.StringToBool(x);
+        }
+        public bool xmrVectorToBool(LSL_Vector x)
+        {
+            return TypeCast.VectorToBool(x);
+        }
+        public bool xmrKeyToBool(string x)
+        {
+            return TypeCast.KeyToBool(x);
+        }
+        public bool xmrListToBool(LSL_List x)
+        {
+            return TypeCast.ListToBool(x);
+        }
+
+        public int xmrStringCompare(string x, string y)
+        {
+            return string.Compare(x, y);
+        }
+
+        /**
+         * @brief types of data we serialize
+         */
+        private enum Ser: byte
+        {
+            NULL,
+            EVENTCODE,
+            LSLFLOAT,
+            LSLINT,
+            LSLKEY,
+            LSLLIST,
+            LSLROT,
+            LSLSTR,
+            LSLVEC,
+            SYSARRAY,
+            SYSDOUB,
+            SYSFLOAT,
+            SYSINT,
+            SYSSTR,
+            XMRARRAY,
+            DUPREF,
+            SYSBOOL,
+            XMRINST,
+            DELEGATE,
+            SDTCLOBJ,
+            SYSCHAR,
+            SYSERIAL,
+            THROWNEX
+        }
+
+        /**
+         * @brief Write state out to a stream.
+         *        Do not change script state.
+         */
+        public void MigrateOut(BinaryWriter mow)
+        {
+            try
+            {
+                this.migrateOutWriter = mow;
+                this.migrateOutObjects = new Dictionary<object, int>();
+                this.migrateOutLists = new Dictionary<object[], ObjLslList>();
+                this.SendObjValue(this.ehArgs);
+                mow.Write(this.doGblInit);
+                mow.Write(this.stateCode);
+                mow.Write((int)this.eventCode);
+                this.glblVars.SendArrays(this.SendObjValue);
+                if(this.newStateCode >= 0)
+                {
+                    mow.Write("**newStateCode**");
+                    mow.Write(this.newStateCode);
+                }
+                for(XMRStackFrame thisSF = this.stackFrames; thisSF != null; thisSF = thisSF.nextSF)
+                {
+                    mow.Write(thisSF.funcName);
+                    mow.Write(thisSF.callNo);
+                    this.SendObjValue(thisSF.objArray);
+                }
+                mow.Write("");
+            }
+            finally
+            {
+                this.migrateOutWriter = null;
+                this.migrateOutObjects = null;
+                this.migrateOutLists = null;
+            }
+        }
+
+        /**
+         * @brief Write an object to the output stream.
+         * @param graph = object to send
+         */
+        private BinaryWriter migrateOutWriter;
+        private Dictionary<object, int> migrateOutObjects;
+        private Dictionary<object[], ObjLslList> migrateOutLists;
+        public void SendObjValue(object graph)
+        {
+            BinaryWriter mow = this.migrateOutWriter;
+
+            /*
+             * Value types (including nulls) are always output directly.
+             */
+            if(graph == null)
+            {
+                mow.Write((byte)Ser.NULL);
+                return;
+            }
+            if(graph is ScriptEventCode)
+            {
+                mow.Write((byte)Ser.EVENTCODE);
+                mow.Write((int)graph);
+                return;
+            }
+            if(graph is LSL_Float)
+            {
+                mow.Write((byte)Ser.LSLFLOAT);
+                mow.Write((double)((LSL_Float)graph).value);
+                return;
+            }
+            if(graph is LSL_Integer)
+            {
+                mow.Write((byte)Ser.LSLINT);
+                mow.Write((int)((LSL_Integer)graph).value);
+                return;
+            }
+            if(graph is LSL_Key)
+            {
+                mow.Write((byte)Ser.LSLKEY);
+                LSL_Key key = (LSL_Key)graph;
+                SendObjValue(key.m_string);  // m_string can be null
+                return;
+            }
+            if(graph is LSL_Rotation)
+            {
+                mow.Write((byte)Ser.LSLROT);
+                mow.Write((double)((LSL_Rotation)graph).x);
+                mow.Write((double)((LSL_Rotation)graph).y);
+                mow.Write((double)((LSL_Rotation)graph).z);
+                mow.Write((double)((LSL_Rotation)graph).s);
+                return;
+            }
+            if(graph is LSL_String)
+            {
+                mow.Write((byte)Ser.LSLSTR);
+                LSL_String str = (LSL_String)graph;
+                SendObjValue(str.m_string);  // m_string can be null
+                return;
+            }
+            if(graph is LSL_Vector)
+            {
+                mow.Write((byte)Ser.LSLVEC);
+                mow.Write((double)((LSL_Vector)graph).x);
+                mow.Write((double)((LSL_Vector)graph).y);
+                mow.Write((double)((LSL_Vector)graph).z);
+                return;
+            }
+            if(graph is bool)
+            {
+                mow.Write((byte)Ser.SYSBOOL);
+                mow.Write((bool)graph);
+                return;
+            }
+            if(graph is double)
+            {
+                mow.Write((byte)Ser.SYSDOUB);
+                mow.Write((double)graph);
+                return;
+            }
+            if(graph is float)
+            {
+                mow.Write((byte)Ser.SYSFLOAT);
+                mow.Write((float)graph);
+                return;
+            }
+            if(graph is int)
+            {
+                mow.Write((byte)Ser.SYSINT);
+                mow.Write((int)graph);
+                return;
+            }
+            if(graph is char)
+            {
+                mow.Write((byte)Ser.SYSCHAR);
+                mow.Write((char)graph);
+                return;
+            }
+
+            /*
+             * Script instance pointer is always just that.
+             */
+            if(graph == this)
+            {
+                mow.Write((byte)Ser.XMRINST);
+                return;
+            }
+
+            /*
+             * Convert lists to object type.
+             * This is compatible with old migration data and also
+             * two vars pointing to same list won't duplicate it.
+             */
+            if(graph is LSL_List)
+            {
+                object[] data = ((LSL_List)graph).Data;
+                ObjLslList oll;
+                if(!this.migrateOutLists.TryGetValue(data, out oll))
+                {
+                    oll = new ObjLslList();
+                    oll.objarray = data;
+                    this.migrateOutLists[data] = oll;
+                }
+                graph = oll;
+            }
+
+            /*
+             * If this same exact object was already serialized,
+             * just output an index telling the receiver to use
+             * that same old object, rather than creating a whole
+             * new object with the same values.  Also this prevents
+             * self-referencing objects (like arrays) from causing
+             * an infinite loop.
+             */
+            int ident;
+            if(this.migrateOutObjects.TryGetValue(graph, out ident))
+            {
+                mow.Write((byte)Ser.DUPREF);
+                mow.Write(ident);
+                return;
+            }
+
+            /*
+             * Object not seen before, save its address with an unique
+             * ident number that the receiver can easily regenerate.
+             */
+            ident = this.migrateOutObjects.Count;
+            this.migrateOutObjects.Add(graph, ident);
+
+            /*
+             * Now output the object's value(s).
+             * If the object self-references, the object is alreay entered
+             * in the dictionary and so the self-reference will just emit
+             * a DUPREF tag instead of trying to output the whole object 
+             * again.
+             */
+            if(graph is ObjLslList)
+            {
+                mow.Write((byte)Ser.LSLLIST);
+                ObjLslList oll = (ObjLslList)graph;
+                SendObjValue(oll.objarray);
+            }
+            else if(graph is XMR_Array)
+            {
+                mow.Write((byte)Ser.XMRARRAY);
+                ((XMR_Array)graph).SendArrayObj(this.SendObjValue);
+            }
+            else if(graph is Array)
+            {
+                Array array = (Array)graph;
+                mow.Write((byte)Ser.SYSARRAY);
+                mow.Write(SysType2String(array.GetType().GetElementType()));
+                mow.Write((int)array.Length);
+                for(int i = 0; i < array.Length; i++)
+                    this.SendObjValue(array.GetValue(i));
+            }
+            else if(graph is string)
+            {
+                mow.Write((byte)Ser.SYSSTR);
+                mow.Write((string)graph);
+            }
+            else if(graph is Delegate)
+            {
+                Delegate del = (Delegate)graph;
+                mow.Write((byte)Ser.DELEGATE);
+                mow.Write(del.Method.Name);
+                Type delType = del.GetType();
+                foreach(KeyValuePair<string, TokenDeclSDType> kvp in m_ObjCode.sdObjTypesName)
+                {
+                    TokenDeclSDType sdt = kvp.Value;
+                    if(sdt is TokenDeclSDTypeDelegate)
+                    {
+                        TokenDeclSDTypeDelegate sdtd = (TokenDeclSDTypeDelegate)sdt;
+                        if(sdtd.GetSysType() == delType)
+                        {
+                            mow.Write(kvp.Key);
+                            goto found;
+                        }
+                    }
+                }
+                throw new Exception("cant find script-defined delegate for " + del.Method.Name + " type " + del.GetType());
+                found:
+                SendObjValue(del.Target);
+            }
+            else if(graph is XMRSDTypeClObj)
+            {
+                mow.Write((byte)Ser.SDTCLOBJ);
+                ((XMRSDTypeClObj)graph).Capture(this.SendObjValue);
+            }
+            else if(graph is ScriptThrownException)
+            {
+                MemoryStream memoryStream = new MemoryStream();
+                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
+                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
+                bformatter.Serialize(memoryStream, graph);
+                byte[] rawBytes = memoryStream.ToArray();
+                mow.Write((byte)Ser.THROWNEX);
+                mow.Write((int)rawBytes.Length);
+                mow.Write(rawBytes);
+                SendObjValue(((ScriptThrownException)graph).thrown);
+            }
+            else
+            {
+                MemoryStream memoryStream = new MemoryStream();
+                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
+                        new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
+                bformatter.Serialize(memoryStream, graph);
+                byte[] rawBytes = memoryStream.ToArray();
+                mow.Write((byte)Ser.SYSERIAL);
+                mow.Write((int)rawBytes.Length);
+                mow.Write(rawBytes);
+            }
+        }
+
+        /**
+         * @brief Use short strings for known type names.
+         */
+        private static string SysType2String(Type type)
+        {
+            if(type.IsArray && (type.GetArrayRank() == 1))
+            {
+                string str = KnownSysType2String(type.GetElementType());
+                if(str != null)
+                    return str + "[]";
+            }
+            else
+            {
+                string str = KnownSysType2String(type);
+                if(str != null)
+                    return str;
+            }
+            return type.ToString();
+        }
+        private static string KnownSysType2String(Type type)
+        {
+            if(type == typeof(bool))
+                return "bo";
+            if(type == typeof(char))
+                return "ch";
+            if(type == typeof(Delegate))
+                return "de";
+            if(type == typeof(double))
+                return "do";
+            if(type == typeof(float))
+                return "fl";
+            if(type == typeof(int))
+                return "in";
+            if(type == typeof(LSL_List))
+                return "li";
+            if(type == typeof(object))
+                return "ob";
+            if(type == typeof(LSL_Rotation))
+                return "ro";
+            if(type == typeof(XMRSDTypeClObj))
+                return "sc";
+            if(type == typeof(string))
+                return "st";
+            if(type == typeof(LSL_Vector))
+                return "ve";
+            if(type == typeof(XMR_Array))
+                return "xa";
+            return null;
+        }
+        private static Type String2SysType(string str)
+        {
+            if(str.EndsWith("[]"))
+                return String2SysType(str.Substring(0, str.Length - 2)).MakeArrayType();
+
+            if(str == "bo")
+                return typeof(bool);
+            if(str == "ch")
+                return typeof(char);
+            if(str == "de")
+                return typeof(Delegate);
+            if(str == "do")
+                return typeof(double);
+            if(str == "fl")
+                return typeof(float);
+            if(str == "in")
+                return typeof(int);
+            if(str == "li")
+                return typeof(LSL_List);
+            if(str == "ob")
+                return typeof(object);
+            if(str == "ro")
+                return typeof(LSL_Rotation);
+            if(str == "sc")
+                return typeof(XMRSDTypeClObj);
+            if(str == "st")
+                return typeof(string);
+            if(str == "ve")
+                return typeof(LSL_Vector);
+            if(str == "xa")
+                return typeof(XMR_Array);
+            return Type.GetType(str, true);
+        }
+
+        /**
+         * @brief Read state in from a stream.
+         */
+        public void MigrateIn(BinaryReader mir)
+        {
+            try
+            {
+                this.migrateInReader = mir;
+                this.migrateInObjects = new Dictionary<int, object>();
+                this.ehArgs = (object[])this.RecvObjValue();
+                this.doGblInit = mir.ReadBoolean();
+                this.stateCode = mir.ReadInt32();
+                this.eventCode = (ScriptEventCode)mir.ReadInt32();
+                this.newStateCode = -1;
+                this.glblVars.RecvArrays(this.RecvObjValue);
+                XMRStackFrame lastSF = null;
+                string funcName;
+                while((funcName = mir.ReadString()) != "")
+                {
+                    if(funcName == "**newStateCode**")
+                    {
+                        this.newStateCode = mir.ReadInt32();
+                        continue;
+                    }
+                    XMRStackFrame thisSF = new XMRStackFrame();
+                    thisSF.funcName = funcName;
+                    thisSF.callNo = mir.ReadInt32();
+                    thisSF.objArray = (object[])this.RecvObjValue();
+                    if(lastSF == null)
+                        this.stackFrames = thisSF;
+                    else
+                        lastSF.nextSF = thisSF;
+                    lastSF = thisSF;
+                }
+            }
+            finally
+            {
+                this.migrateInReader = null;
+                this.migrateInObjects = null;
+            }
+        }
+
+        /**
+         * @brief Read a single value from the stream.
+         * @returns value (boxed as needed)
+         */
+        private BinaryReader migrateInReader;
+        private Dictionary<int, object> migrateInObjects;
+        public object RecvObjValue()
+        {
+            BinaryReader mir = this.migrateInReader;
+            int ident = this.migrateInObjects.Count;
+            Ser code = (Ser)mir.ReadByte();
+            switch(code)
+            {
+                case Ser.NULL:
+                    return null;
+
+                case Ser.EVENTCODE:
+                    return (ScriptEventCode)mir.ReadInt32();
+
+                case Ser.LSLFLOAT:
+                    return new LSL_Float(mir.ReadDouble());
+
+                case Ser.LSLINT:
+                    return new LSL_Integer(mir.ReadInt32());
+
+                case Ser.LSLKEY:
+                    return new LSL_Key((string)RecvObjValue());
+
+                case Ser.LSLLIST:
+                    {
+                        this.migrateInObjects.Add(ident, null);    // placeholder
+                        object[] data = (object[])RecvObjValue();  // read data, maybe using another index
+                        LSL_List list = new LSL_List(data);        // make LSL-level list
+                        this.migrateInObjects[ident] = list;        // fill in slot
+                        return list;
+                    }
+
+                case Ser.LSLROT:
+                    {
+                        double x = mir.ReadDouble();
+                        double y = mir.ReadDouble();
+                        double z = mir.ReadDouble();
+                        double w = mir.ReadDouble();
+                        return new LSL_Rotation(x, y, z, w);
+                    }
+                case Ser.LSLSTR:
+                    return new LSL_String((string)RecvObjValue());
+
+                case Ser.LSLVEC:
+                    {
+                        double x = mir.ReadDouble();
+                        double y = mir.ReadDouble();
+                        double z = mir.ReadDouble();
+                        return new LSL_Vector(x, y, z);
+                    }
+
+                case Ser.SYSARRAY:
+                    {
+                        Type eletype = String2SysType(mir.ReadString());
+                        int length = mir.ReadInt32();
+                        Array array = Array.CreateInstance(eletype, length);
+                        this.migrateInObjects.Add(ident, array);
+                        for(int i = 0; i < length; i++)
+                            array.SetValue(RecvObjValue(), i);
+                        return array;
+                    }
+
+                case Ser.SYSBOOL:
+                    return mir.ReadBoolean();
+
+                case Ser.SYSDOUB:
+                    return mir.ReadDouble();
+
+                case Ser.SYSFLOAT:
+                    return mir.ReadSingle();
+
+                case Ser.SYSINT:
+                    return mir.ReadInt32();
+
+                case Ser.SYSCHAR:
+                    return mir.ReadChar();
+
+                case Ser.SYSSTR:
+                    string s = mir.ReadString();
+                    this.migrateInObjects.Add(ident, s);
+                    return s;
+
+                case Ser.XMRARRAY:
+                    {
+                        XMR_Array array = new XMR_Array(this);
+                        this.migrateInObjects.Add(ident, array);
+                        array.RecvArrayObj(this.RecvObjValue);
+                        return array;
+                    }
+
+                case Ser.DUPREF:
+                    {
+                        ident = mir.ReadInt32();
+                        object obj = this.migrateInObjects[ident];
+                        if(obj is ObjLslList)
+                            obj = new LSL_List(((ObjLslList)obj).objarray);
+                        return obj;
+                    }
+
+                case Ser.XMRINST:
+                    return this;
+
+                case Ser.DELEGATE:
+                    this.migrateInObjects.Add(ident, null);  // placeholder
+                    string name = mir.ReadString();         // function name
+                    string sig = mir.ReadString();         // delegate type
+                    object targ = this.RecvObjValue();      // 'this' object
+                    Delegate del = this.GetScriptMethodDelegate(name, sig, targ);
+                    this.migrateInObjects[ident] = del;       // actual value
+                    return del;
+
+                case Ser.SDTCLOBJ:
+                    XMRSDTypeClObj clobj = new XMRSDTypeClObj();
+                    this.migrateInObjects.Add(ident, clobj);
+                    clobj.Restore(this, this.RecvObjValue);
+                    return clobj;
+
+                case Ser.SYSERIAL:
+                    {
+                        int rawLength = mir.ReadInt32();
+                        byte[] rawBytes = mir.ReadBytes(rawLength);
+                        MemoryStream memoryStream = new MemoryStream(rawBytes);
+                        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
+                                new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
+                        object graph = bformatter.Deserialize(memoryStream);
+                        this.migrateInObjects.Add(ident, graph);
+                        return graph;
+                    }
+
+                case Ser.THROWNEX:
+                    {
+                        int rawLength = mir.ReadInt32();
+                        byte[] rawBytes = mir.ReadBytes(rawLength);
+                        MemoryStream memoryStream = new MemoryStream(rawBytes);
+                        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
+                                new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
+                        object graph = bformatter.Deserialize(memoryStream);
+                        this.migrateInObjects.Add(ident, graph);
+                        ((ScriptThrownException)graph).thrown = RecvObjValue();
+                        return graph;
+                    }
+
+                default:
+                    throw new Exception("bad stream code " + code.ToString());
+            }
+        }
+
+        // wrapper around list object arrays to make sure they are always object types for migration purposes
+        private class ObjLslList
+        {
+            public object[] objarray;
+        }
+    }
+
+    // Any xmr...() methods that call CheckRun() must be tagged with this attribute
+    // so the ScriptCodeGen will know the method is non-trivial.
+    public class xmrMethodCallsCheckRunAttribute: Attribute
+    {
+    }
+
+    // Any xmr...() methods in xmrengtest that call Stub<somethingorother>() must be 
+    // tagged with this attribute so the -builtins option will tell the user that 
+    // they are a stub function.
+    public class xmrMethodIsNoisyAttribute: Attribute
+    {
+    }
+
+    // Any script callable methods that really return a key not a string should be
+    // tagged with this attribute so the compiler will know they return type key and
+    // not type string.
+    public class xmrMethodReturnsKeyAttribute: Attribute
+    {
+    }
+
+    [SerializableAttribute]
+    public class OutOfHeapException: Exception
+    {
+        public OutOfHeapException(int oldtotal, int newtotal, int limit)
+                : base("oldtotal=" + oldtotal + ", newtotal=" + newtotal + ", limit=" + limit)
+        {
+        }
+    }
+
+    [SerializableAttribute]
+    public class OutOfStackException: Exception
+    {
+    }
+}

+ 201 - 206
OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs

@@ -42,13 +42,13 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /****************************************************\
      *  This file contains routines called by scripts.  *
     \****************************************************/
 
-    public class XMRLSL_Api : LSL_Api
+    public class XMRLSL_Api: LSL_Api
     {
         public AsyncCommandManager acm;
         private XMRInstance inst;
@@ -83,38 +83,38 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *         -2: no av granted perms
          *         -3: av not in region
          */
-/* engines should not have own API
-        public int xmrSeatAvatar (bool owner)
-        {
-            // Get avatar to be seated and make sure they have given us ANIMATION permission
-
-            UUID avuuid;
-            if (owner) {
-                avuuid = inst.m_Part.OwnerID;
-            } else {
-                if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
-                    return -1;
-                }
-                avuuid = m_item.PermsGranter;
-            }
-            if (avuuid == UUID.Zero) {
-                return -2;
-            }
+        /* engines should not have own API
+                public int xmrSeatAvatar (bool owner)
+                {
+                    // Get avatar to be seated and make sure they have given us ANIMATION permission
+
+                    UUID avuuid;
+                    if (owner) {
+                        avuuid = inst.m_Part.OwnerID;
+                    } else {
+                        if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
+                            return -1;
+                        }
+                        avuuid = m_item.PermsGranter;
+                    }
+                    if (avuuid == UUID.Zero) {
+                        return -2;
+                    }
 
-            ScenePresence presence = World.GetScenePresence (avuuid);
-            if (presence == null) {
-                return -3;
-            }
+                    ScenePresence presence = World.GetScenePresence (avuuid);
+                    if (presence == null) {
+                        return -3;
+                    }
 
-            // remoteClient = not used by ScenePresence.HandleAgentRequestSit()
-            //      agentID = not used by ScenePresence.HandleAgentRequestSit()
-            //     targetID = UUID of prim to sit on
-            //       offset = offset of sitting position
+                    // remoteClient = not used by ScenePresence.HandleAgentRequestSit()
+                    //      agentID = not used by ScenePresence.HandleAgentRequestSit()
+                    //     targetID = UUID of prim to sit on
+                    //       offset = offset of sitting position
 
-            presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
-            return 0;
-        }
-*/
+                    presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
+                    return 0;
+                }
+        */
         /**
          * @brief llTeleportAgent() is broken in that if you pass it a landmark,
          *        it still subjects the position to spawn points, as it always
@@ -125,80 +125,80 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param landmark = inventory name or UUID of a landmark object
          * @param lookat   = looking direction after teleport
          */
-/* engines should not have own API
-        public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
-        {
-            // find out about agent to be teleported
-            UUID agentId;
-            if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
-
-            ScenePresence presence = World.GetScenePresence (agentId);
-            if (presence == null) throw new ApplicationException ("agent not present in scene");
-            if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
-            if (presence.IsGod) throw new ApplicationException ("agent is a god");
-
-            // prim must be owned by land owner or prim must be attached to agent
-            if (m_host.ParentGroup.AttachmentPoint == 0) {
-                if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
-                    throw new ApplicationException ("prim not owned by land's owner");
-                }
-            } else {
-                if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
-            }
+        /* engines should not have own API
+                public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
+                {
+                    // find out about agent to be teleported
+                    UUID agentId;
+                    if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
+
+                    ScenePresence presence = World.GetScenePresence (agentId);
+                    if (presence == null) throw new ApplicationException ("agent not present in scene");
+                    if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
+                    if (presence.IsGod) throw new ApplicationException ("agent is a god");
+
+                    // prim must be owned by land owner or prim must be attached to agent
+                    if (m_host.ParentGroup.AttachmentPoint == 0) {
+                        if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
+                            throw new ApplicationException ("prim not owned by land's owner");
+                        }
+                    } else {
+                        if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
+                    }
 
-            // find landmark in inventory or by UUID
-            UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
-            if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
+                    // find landmark in inventory or by UUID
+                    UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
+                    if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
 
-            // read it in and make sure it is a landmark
-            AssetBase lma = World.AssetService.Get (assetID.ToString ());
-            if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
+                    // read it in and make sure it is a landmark
+                    AssetBase lma = World.AssetService.Get (assetID.ToString ());
+                    if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
 
-            // parse the record
-            AssetLandmark lm = new AssetLandmark (lma);
+                    // parse the record
+                    AssetLandmark lm = new AssetLandmark (lma);
 
-            // the regionhandle (based on region's world X,Y) might be out of date
-            // re-read the handle so we can pass it to RequestTeleportLocation()
-            var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
-            if (region == null) throw new ApplicationException ("no such region");
+                    // the regionhandle (based on region's world X,Y) might be out of date
+                    // re-read the handle so we can pass it to RequestTeleportLocation()
+                    var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
+                    if (region == null) throw new ApplicationException ("no such region");
 
-            // finally ready to teleport
-            World.RequestTeleportLocation (presence.ControllingClient,
-                                           region.RegionHandle,
-                                           lm.Position,
-                                           lookat,
-                                           (uint)TeleportFlags.ViaLandmark);
-        }
-*/
+                    // finally ready to teleport
+                    World.RequestTeleportLocation (presence.ControllingClient,
+                                                   region.RegionHandle,
+                                                   lm.Position,
+                                                   lookat,
+                                                   (uint)TeleportFlags.ViaLandmark);
+                }
+        */
         /**
          * @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL.
          *        Code modelled after llSetParcelMusicURL().
          * @param newurl = new URL to set (or "" to leave it alone)
          * @returns previous URL string
          */
-/* engines should not have own API
-        public string xmrSetParcelMusicURLGroup (string newurl)
-        {
-            string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
-            if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
+        /* engines should not have own API
+                public string xmrSetParcelMusicURLGroup (string newurl)
+                {
+                    string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
+                    if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
 
-            IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
-            if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
+                    IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
+                    if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
 
-            GroupRecord grouprec = igm.GetGroupRecord (groupname);
-            if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
+                    GroupRecord grouprec = igm.GetGroupRecord (groupname);
+                    if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
 
-            GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
-            if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
+                    GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
+                    if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
 
-            ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
-            if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
-            string oldurl = land.GetMusicUrl ();
-            if (oldurl == null) oldurl = "";
-            if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
-            return oldurl;
-        }
-*/
+                    ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
+                    if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
+                    string oldurl = land.GetMusicUrl ();
+                    if (oldurl == null) oldurl = "";
+                    if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
+                    return oldurl;
+                }
+        */
     }
 
     public partial class XMRInstance
@@ -222,9 +222,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public DetectParams GetDetectParams(int number)
         {
             DetectParams dp = null;
-            if ((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length)) {
+            if((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length))
                 dp = m_DetectParams[number];
-            }
+
             return dp;
         }
 
@@ -236,7 +236,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public void Die()
         {
             // llDie doesn't work in attachments!
-            if (m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
+            if(m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
                 return;
 
             throw new ScriptDieException();
@@ -247,8 +247,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public void Sleep(int ms)
         {
-            lock (m_QueueLock) {
-
+            lock(m_QueueLock)
+            {
                 /*
                  * Say how long to sleep.
                  */
@@ -306,12 +306,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *      be returned by xmrEventDequeue, to let the runtime know that the script is capable
          *      of processing that event type.  Otherwise, the event may not be queued to the script.
          */
-        private static LSL_List emptyList = new LSL_List (new object[0]);
+        private static LSL_List emptyList = new LSL_List(new object[0]);
 
-        public override LSL_List xmrEventDequeue (double timeout, int returnMask1, int returnMask2,
+        public override LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
                                                   int backgroundMask1, int backgroundMask2)
         {
-            DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds (timeout * 1000.0);
+            DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
             EventParams evt = null;
             int callNo, evc2;
             int evc1 = 0;
@@ -324,45 +324,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             callNo = -1;
             try
             {
-                if (callMode == CallMode_NORMAL) goto findevent;
+                if(callMode == CallMode_NORMAL)
+                    goto findevent;
 
                 /*
                  * Stack frame is being restored as saved via CheckRun...().
                  * Restore necessary values then jump to __call<n> label to resume processing.
                  */
-                sv          = RestoreStackFrame ("xmrEventDequeue", out callNo);
-                sleepUntil  = DateTime.Parse ((string)sv[0]);
+                sv = RestoreStackFrame("xmrEventDequeue", out callNo);
+                sleepUntil = DateTime.Parse((string)sv[0]);
                 returnMask1 = (int)sv[1];
                 returnMask2 = (int)sv[2];
-                mask1       = (int)sv[3];
-                mask2       = (int)sv[4];
-                switch (callNo)
+                mask1 = (int)sv[3];
+                mask2 = (int)sv[4];
+                switch(callNo)
                 {
-                    case 0: goto __call0;
+                    case 0:
+                        goto __call0;
                     case 1:
-                    {
-                        evc1 = (int)sv[5];
-                        evc  = (ScriptEventCode)(int)sv[6];
-                        DetectParams[] detprms = ObjArrToDetPrms ((object[])sv[7]);
-                        object[]       ehargs  = (object[])sv[8];
-                        evt = new EventParams (evc.ToString (), ehargs, detprms);
-                        goto __call1;
-                    }
+                        {
+                            evc1 = (int)sv[5];
+                            evc = (ScriptEventCode)(int)sv[6];
+                            DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
+                            object[] ehargs = (object[])sv[8];
+                            evt = new EventParams(evc.ToString(), ehargs, detprms);
+                            goto __call1;
+                        }
                 }
-                throw new ScriptBadCallNoException (callNo);
+                throw new ScriptBadCallNoException(callNo);
 
                 /*
                  * Find first event that matches either the return or background masks.
                  */
-            findevent:
-                Monitor.Enter (m_QueueLock);
-                for (lln = m_EventQueue.First; lln != null; lln = lln.Next)
+                findevent:
+                Monitor.Enter(m_QueueLock);
+                for(lln = m_EventQueue.First; lln != null; lln = lln.Next)
                 {
-                    evt  = lln.Value;
-                    evc  = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), evt.EventName);
+                    evt = lln.Value;
+                    evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
                     evc1 = (int)evc;
                     evc2 = evc1 - 32;
-                    if ((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
+                    if((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
                         (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0)))
                         goto remfromq;
                 }
@@ -373,51 +375,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 m_SleepUntil = sleepUntil;
                 m_SleepEventMask1 = mask1;
                 m_SleepEventMask2 = mask2;
-                Monitor.Exit (m_QueueLock);
+                Monitor.Exit(m_QueueLock);
                 suspendOnCheckRunTemp = true;
                 callNo = 0;
-            __call0:
-                CheckRunQuick ();
+                __call0:
+                CheckRunQuick();
                 goto checktmo;
 
                 /*
                  * Found one, remove it from queue.
                  */
-            remfromq:
-                m_EventQueue.Remove (lln);
-                if ((uint)evc1 < (uint)m_EventCounts.Length)
-                    m_EventCounts[evc1] --;
+                remfromq:
+                m_EventQueue.Remove(lln);
+                if((uint)evc1 < (uint)m_EventCounts.Length)
+                    m_EventCounts[evc1]--;
 
-                Monitor.Exit (m_QueueLock);
-                m_InstEHEvent ++;
+                Monitor.Exit(m_QueueLock);
+                m_InstEHEvent++;
 
                 /*
                  * See if returnable or background event.
                  */
-                if ((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
+                if((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
                     (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0)))
                 {
-
                     /*
                      * Returnable event, return its parameters in a list.
                      * Also set the detect parameters to what the event has.
                      */
                     int plen = evt.Params.Length;
-                    object[] plist = new object[plen+1];
+                    object[] plist = new object[plen + 1];
                     plist[0] = (LSL_Integer)evc1;
-                    for (int i = 0; i < plen;)
+                    for(int i = 0; i < plen;)
                     {
                         object ob = evt.Params[i];
-                        if (ob is int)
+                        if(ob is int)
                             ob = (LSL_Integer)(int)ob;
-                        else if (ob is double)
+                        else if(ob is double)
                             ob = (LSL_Float)(double)ob;
-                        else if (ob is string)
+                        else if(ob is string)
                             ob = (LSL_String)(string)ob;
                         plist[++i] = ob;
                     }
                     m_DetectParams = evt.DetectParams;
-                    return new LSL_List (plist);
+                    return new LSL_List(plist);
                 }
 
                 /*
@@ -425,35 +426,35 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                  * then check event queue again.
                  */
                 callNo = 1;
-            __call1:
-                ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc1];
-                if (seh == null)
+                __call1:
+                ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
+                if(seh == null)
                     goto checktmo;
 
-                DetectParams[]  saveDetParams = this.m_DetectParams;
-                object[]        saveEHArgs    = this.ehArgs;
+                DetectParams[] saveDetParams = this.m_DetectParams;
+                object[] saveEHArgs = this.ehArgs;
                 ScriptEventCode saveEventCode = this.eventCode;
 
                 this.m_DetectParams = evt.DetectParams;
-                this.ehArgs         = evt.Params;
-                this.eventCode      = evc;
+                this.ehArgs = evt.Params;
+                this.eventCode = evc;
 
                 try
                 {
-                    seh (this);
+                    seh(this);
                 }
                 finally
                 {
-                    m_DetectParams = saveDetParams;
-                    ehArgs         = saveEHArgs;
-                    eventCode      = saveEventCode;
+                    this.m_DetectParams = saveDetParams;
+                    this.ehArgs = saveEHArgs;
+                    this.eventCode = saveEventCode;
                 }
 
                 /*
                  * Keep waiting until we find a returnable event or timeout.
                  */
-            checktmo:
-                if (DateTime.UtcNow < sleepUntil)
+                checktmo:
+                if(DateTime.UtcNow < sleepUntil)
                     goto findevent;
 
                 /*
@@ -463,7 +464,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             }
             finally
             {
-                if (callMode != CallMode_NORMAL)
+                if(callMode != CallMode_NORMAL)
                 {
 
                     /*
@@ -471,17 +472,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                      * Save everything we need at the __call<n> labels so we can restore it
                      * when we need to.
                      */
-                    sv    = CaptureStackFrame ("xmrEventDequeue", callNo, 9);
-                    sv[0] = sleepUntil.ToString ();                  // needed at __call0,__call1
+                    sv = CaptureStackFrame("xmrEventDequeue", callNo, 9);
+                    sv[0] = sleepUntil.ToString();                  // needed at __call0,__call1
                     sv[1] = returnMask1;                             // needed at __call0,__call1
                     sv[2] = returnMask2;                             // needed at __call0,__call1
                     sv[3] = mask1;                                   // needed at __call0,__call1
                     sv[4] = mask2;                                   // needed at __call0,__call1
-                    if (callNo == 1)
+                    if(callNo == 1)
                     {
                         sv[5] = evc1;                                // needed at __call1
                         sv[6] = (int)evc;                            // needed at __call1
-                        sv[7] = DetPrmsToObjArr (evt.DetectParams);  // needed at __call1
+                        sv[7] = DetPrmsToObjArr(evt.DetectParams);  // needed at __call1
                         sv[8] = evt.Params;                          // needed at __call1
                     }
                 }
@@ -495,16 +496,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          *             are as currently set for the script (use xmrEventLoadDets to set how
          *             you want them to be different).
          */
-        public override void xmrEventEnqueue (LSL_List ev)
+        public override void xmrEventEnqueue(LSL_List ev)
         {
             object[] data = ev.Data;
-            ScriptEventCode evc = (ScriptEventCode)ListInt (data[0]);
+            ScriptEventCode evc = (ScriptEventCode)ListInt(data[0]);
 
             int nargs = data.Length - 1;
             object[] args = new object[nargs];
-            Array.Copy (data, 1, args, 0, nargs);
+            Array.Copy(data, 1, args, 0, nargs);
 
-            PostEvent (new EventParams (evc.ToString (), args, m_DetectParams));
+            PostEvent(new EventParams(evc.ToString(), args, m_DetectParams));
         }
 
         /**
@@ -513,19 +514,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private const int saveDPVer = 1;
 
-        public override LSL_List xmrEventSaveDets ()
+        public override LSL_List xmrEventSaveDets()
         {
-            object[] obs = DetPrmsToObjArr (m_DetectParams);
-            return new LSL_List (obs);
+            object[] obs = DetPrmsToObjArr(m_DetectParams);
+            return new LSL_List(obs);
         }
 
-        private static object[] DetPrmsToObjArr (DetectParams[] dps)
+        private static object[] DetPrmsToObjArr(DetectParams[] dps)
         {
             int len = dps.Length;
-            object[] obs = new object[len*16+1];
+            object[] obs = new object[len * 16 + 1];
             int j = 0;
             obs[j++] = (LSL_Integer)saveDPVer;
-            for (int i = 0; i < len; i ++)
+            for(int i = 0; i < len; i++)
             {
                 DetectParams dp = dps[i];
                 obs[j++] = (LSL_String)dp.Key.ToString();    // UUID
@@ -548,54 +549,52 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             return obs;
         }
 
-
         /**
          * @brief Load current detect params from a list
          * @param dpList = as returned by xmrEventSaveDets()
          */
-        public override void xmrEventLoadDets (LSL_List dpList)
+        public override void xmrEventLoadDets(LSL_List dpList)
         {
-            m_DetectParams = ObjArrToDetPrms (dpList.Data);
+            m_DetectParams = ObjArrToDetPrms(dpList.Data);
         }
 
-        private static DetectParams[] ObjArrToDetPrms (object[] objs)
+        private static DetectParams[] ObjArrToDetPrms(object[] objs)
         {
             int j = 0;
-            if ((objs.Length % 16 != 1) || (ListInt (objs[j++]) != saveDPVer))
-                throw new Exception ("invalid detect param format");
+            if((objs.Length % 16 != 1) || (ListInt(objs[j++]) != saveDPVer))
+                throw new Exception("invalid detect param format");
 
             int len = objs.Length / 16;
             DetectParams[] dps = new DetectParams[len];
 
-            for (int i = 0; i < len; i ++)
+            for(int i = 0; i < len; i++)
             {
-                DetectParams dp = new DetectParams ();
-
-                dp.Key         = new UUID (ListStr (objs[j++]));
-                dp.OffsetPos   = (LSL_Vector)objs[j++];
-                dp.LinkNum     = ListInt (objs[j++]);
-                dp.Group       = new UUID (ListStr (objs[j++]));
-                dp.Name        = ListStr (objs[j++]);
-                dp.Owner       = new UUID (ListStr (objs[j++]));
-                dp.Position    = (LSL_Vector)objs[j++];
-                dp.Rotation    = (LSL_Rotation)objs[j++];
-                dp.Type        = ListInt (objs[j++]);
-                dp.Velocity    = (LSL_Vector)objs[j++];
-
-                SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs ();
-
-                stea.STCoord   = LSLVec2OMVec ((LSL_Vector)objs[j++]);
-                stea.Normal    = LSLVec2OMVec ((LSL_Vector)objs[j++]);
-                stea.Binormal  = LSLVec2OMVec ((LSL_Vector)objs[j++]);
-                stea.Position  = LSLVec2OMVec ((LSL_Vector)objs[j++]);
-                stea.UVCoord   = LSLVec2OMVec ((LSL_Vector)objs[j++]);
-                stea.FaceIndex = ListInt (objs[j++]);
+                DetectParams dp = new DetectParams();
+
+                dp.Key = new UUID(ListStr(objs[j++]));
+                dp.OffsetPos = (LSL_Vector)objs[j++];
+                dp.LinkNum = ListInt(objs[j++]);
+                dp.Group = new UUID(ListStr(objs[j++]));
+                dp.Name = ListStr(objs[j++]);
+                dp.Owner = new UUID(ListStr(objs[j++]));
+                dp.Position = (LSL_Vector)objs[j++];
+                dp.Rotation = (LSL_Rotation)objs[j++];
+                dp.Type = ListInt(objs[j++]);
+                dp.Velocity = (LSL_Vector)objs[j++];
+
+                SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs();
+
+                stea.STCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
+                stea.Normal = LSLVec2OMVec((LSL_Vector)objs[j++]);
+                stea.Binormal = LSLVec2OMVec((LSL_Vector)objs[j++]);
+                stea.Position = LSLVec2OMVec((LSL_Vector)objs[j++]);
+                stea.UVCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
+                stea.FaceIndex = ListInt(objs[j++]);
 
                 dp.SurfaceTouchArgs = stea;
 
                 dps[i] = dp;
             }
-
             return dps;
         }
 
@@ -623,21 +622,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             /*
              * Clear out any old events from the queue.
              */
-            lock (m_QueueLock)
+            lock(m_QueueLock)
             {
                 m_EventQueue.Clear();
-                for (int i = m_EventCounts.Length; -- i >= 0;)
+                for(int i = m_EventCounts.Length; --i >= 0;)
                     m_EventCounts[i] = 0;
             }
         }
-
-        /**
-         * @brief Script is calling xmrStackLeft().
-         */
-        public override int xmrStackLeft ()
-        {
-            return microthread.StackLeft ();
-        }
     }
 
     /**
@@ -646,12 +637,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
      *        handler.  We don't want script-level try/catch to intercept
      *        these so scripts can't interfere with the behavior.
      */
-    public class ScriptResetException : Exception, IXMRUncatchable { }
+    public class ScriptResetException: Exception, IXMRUncatchable
+    {
+    }
 
     /**
      * @brief Thrown by things like llDie() to unconditionally unwind as 
      *        script.  We don't want script-level try/catch to intercept
      *        these so scripts can't interfere with the behavior.
      */
-    public class ScriptDieException : Exception, IXMRUncatchable { }
+    public class ScriptDieException: Exception, IXMRUncatchable
+    {
+    }
 }

+ 54 - 148
OpenSim/Region/ScriptEngine/XMREngine/XMRInstCapture.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstCapture.cs

@@ -26,7 +26,6 @@
  */
 
 using System;
-using System.Threading;
 using System.IO;
 using System.Xml;
 using OpenSim.Region.ScriptEngine.Shared;
@@ -41,7 +40,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public partial class XMRInstance
     {
@@ -54,7 +53,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
         /**
          * @brief Create an XML element that gives the current state of the script.
-         *   <ScriptState Engine="XMREngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID>
+         *   <ScriptState Engine="YEngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID>
          *     <Snapshot>globalsandstackdump</Snapshot>
          *     <Running>m_Running</Running>
          *     <DetectArray ...
@@ -71,23 +70,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             // Change this to a 5 second timeout. If things do mess up,
             // we don't want to be stuck forever.
             //
-            m_DetachReady.WaitOne (5000, false);
+            m_DetachReady.WaitOne(5000, false);
 
             XmlElement scriptStateN = doc.CreateElement("", "ScriptState", "");
             scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName);
             scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString());
-            scriptStateN.SetAttribute ("SourceHash", m_ObjCode.sourceHash);
+            scriptStateN.SetAttribute("SourceHash", m_ObjCode.sourceHash);
 
-             // Make sure we aren't executing part of the script so it stays 
-             // stable.  Setting suspendOnCheckRun tells CheckRun() to suspend
-             // and return out so RunOne() will release the lock asap.
+            // Make sure we aren't executing part of the script so it stays 
+            // stable.  Setting suspendOnCheckRun tells CheckRun() to suspend
+            // and return out so RunOne() will release the lock asap.
             suspendOnCheckRunHold = true;
-            lock (m_RunLock)
+            lock(m_RunLock)
             {
                 m_RunOnePhase = "GetExecutionState enter";
                 CheckRunLockInvariants(true);
 
-                 // Get copy of script globals and stack in relocateable form.
+                // Get copy of script globals and stack in relocateable form.
                 MemoryStream snapshotStream = new MemoryStream();
                 MigrateOutEventHandler(snapshotStream);
                 Byte[] snapshotBytes = snapshotStream.ToArray();
@@ -96,21 +95,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 XmlElement snapshotN = doc.CreateElement("", "Snapshot", "");
                 snapshotN.AppendChild(doc.CreateTextNode(snapshotString));
                 scriptStateN.AppendChild(snapshotN);
-                m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState B";
+                CheckRunLockInvariants(true);
 
-                 // "Running" says whether or not we are accepting new events.
+                // "Running" says whether or not we are accepting new events.
                 XmlElement runningN = doc.CreateElement("", "Running", "");
                 runningN.AppendChild(doc.CreateTextNode(m_Running.ToString()));
                 scriptStateN.AppendChild(runningN);
-                m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState C";
+                CheckRunLockInvariants(true);
 
-                 // "DoGblInit" says whether or not default:state_entry() will init global vars.
+                // "DoGblInit" says whether or not default:state_entry() will init global vars.
                 XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", "");
                 doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString()));
                 scriptStateN.AppendChild(doGblInitN);
-                m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState D";
+                CheckRunLockInvariants(true);
 
-                 // More misc data.
+                // More misc data.
                 XmlNode permissionsN = doc.CreateElement("", "Permissions", "");
                 scriptStateN.AppendChild(permissionsN);
 
@@ -121,30 +123,32 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 XmlAttribute maskA = doc.CreateAttribute("", "mask", "");
                 maskA.Value = m_Item.PermsMask.ToString();
                 permissionsN.Attributes.Append(maskA);
-                m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState E";
+                CheckRunLockInvariants(true);
 
-                 // "DetectParams" are returned by llDetected...() script functions
-                 // for the currently active event, if any.
-                if (m_DetectParams != null)
+                // "DetectParams" are returned by llDetected...() script functions
+                // for the currently active event, if any.
+                if(m_DetectParams != null)
                 {
                     XmlElement detParArrayN = doc.CreateElement("", "DetectArray", "");
                     AppendXMLDetectArray(doc, detParArrayN, m_DetectParams);
                     scriptStateN.AppendChild(detParArrayN);
                 }
-                m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true);
-
-                 // Save any events we have in the queue.
-                 // <EventQueue>
-                 //   <Event Name="...">
-                 //     <param>...</param> ...
-                 //     <DetectParams>...</DetectParams> ...
-                 //   </Event>
-                 //   ...
-                 // </EventQueue>
+                m_RunOnePhase = "GetExecutionState F";
+                CheckRunLockInvariants(true);
+
+                // Save any events we have in the queue.
+                // <EventQueue>
+                //   <Event Name="...">
+                //     <param>...</param> ...
+                //     <DetectParams>...</DetectParams> ...
+                //   </Event>
+                //   ...
+                // </EventQueue>
                 XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", "");
-                lock (m_QueueLock)
+                lock(m_QueueLock)
                 {
-                    foreach (EventParams evt in m_EventQueue)
+                    foreach(EventParams evt in m_EventQueue)
                     {
                         XmlElement singleEventN = doc.CreateElement("", "Event", "");
                         singleEventN.SetAttribute("Name", evt.EventName);
@@ -154,26 +158,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                     }
                 }
                 scriptStateN.AppendChild(queuedEventsN);
-                m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState G";
+                CheckRunLockInvariants(true);
 
-                 // "Plugins" indicate enabled timers and listens, etc.
-                Object[] pluginData = 
+                // "Plugins" indicate enabled timers and listens, etc.
+                Object[] pluginData =
                         AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
 
                 XmlNode plugins = doc.CreateElement("", "Plugins", "");
                 AppendXMLObjectArray(doc, plugins, pluginData, "plugin");
                 scriptStateN.AppendChild(plugins);
-                m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true);
+                m_RunOnePhase = "GetExecutionState H";
+                CheckRunLockInvariants(true);
 
-                 // Let script run again.
+                // Let script run again.
                 suspendOnCheckRunHold = false;
 
                 m_RunOnePhase = "GetExecutionState leave";
                 CheckRunLockInvariants(true);
             }
 
-             // scriptStateN represents the contents of the .state file so
-             // write the .state file while we are here.
+            // scriptStateN represents the contents of the .state file so
+            // write the .state file while we are here.
             FileStream fs = File.Create(m_StateFileName);
             StreamWriter sw = new StreamWriter(fs);
             sw.Write(scriptStateN.OuterXml);
@@ -185,116 +191,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
         /**
          * @brief Write script state to output stream.
-         *        The script microthread is at same state on return,
-         *        ie, either inactive or suspended inside CheckRun().
-         *
          * Input:
          *  stream = stream to write event handler state information to
          */
-        private void MigrateOutEventHandler (Stream stream)
+        private void MigrateOutEventHandler(Stream stream)
         {
-            moehexcep = null;
-
-            // do all the work in the MigrateOutEventHandlerThread() method below
-            moehstream = stream;
-
-            XMRScriptThread cst = m_Engine.CurrentScriptThread ();
-            if (cst != null)
-            {
-
-                // we might be getting called inside some LSL Api function
-                // so we are already in script thread and thus must do
-                // migration directly
-                MigrateOutEventHandlerThread ();
-            }
-            else
-            {
-                // some other thread, do migration via a script thread
-                m_Engine.QueueToTrunk(this.MigrateOutEventHandlerThread);
-
-                // wait for it to complete
-                lock (moehdone)
-                {
-                    while (moehstream != null)
-                        Monitor.Wait (moehdone);
-                }
-            }
-
-            // maybe it threw up
-            if (moehexcep != null)
-                throw moehexcep;
-        }
-
-        private Exception moehexcep;
-        private object moehdone = new object ();
-        private Stream moehstream;
-        private void MigrateOutEventHandlerThread ()
-        {
-            Exception except;
-
-            try
-            {
-                 // Resume the microthread and it will throw a StackCaptureException()
-                 // with the stack frames saved to this.stackFrames.
-                 // Then write the saved stack frames to the output stream.
-                 //
-                 // There is a stack only if the event code is not None.
-                if (this.eventCode != ScriptEventCode.None)
-                {
-                    // tell microthread to continue
-                    // it should see captureStackFrames and throw StackCaptureException()
-                    // ...generating XMRStackFrames as it unwinds
-                    this.captureStackFrames = true;
-//                    this.suspendOnCheckRunTemp = true;
-                    except = this.microthread.ResumeEx ();
-                    this.captureStackFrames = false;
-
-                    if (except == null)
-                        throw new Exception ("stack save did not complete");
-
-                    if (!(except is StackCaptureException))
-                        throw except;
-                }
-
-                 // Write script state out, frames and all, to the stream.
-                 // Does not change script state.
-
-                moehstream.WriteByte (migrationVersion);
-                moehstream.WriteByte ((byte)16);
-                this.MigrateOut (new BinaryWriter (moehstream));
-
-                 // Now restore script stack.
-                 // Microthread will suspend inside CheckRun() when restore is complete.
-                if (this.eventCode != ScriptEventCode.None)
-                {
-                    this.stackFramesRestored = false;
-                    except = this.microthread.StartEx ();
-
-                    if (except != null)
-                        throw except;
-
-                    if (!this.stackFramesRestored)
-                        throw new Exception ("restore after save did not complete");
-
-                }
-            }
-            catch (Exception e)
-            {
-                moehexcep = e;
-            }
-            finally
-            {
-                // make sure CheckRunLockInvariants() won't puque
-                if (this.microthread.Active () == 0)
-                    this.eventCode = ScriptEventCode.None;
-
-                // wake the MigrateOutEventHandler() method above
-                lock (moehdone)
-                {
-                    moehstream = null;
-                    Monitor.Pulse (moehdone);
-                }
-            }
+            // Write script state out, frames and all, to the stream.
+            // Does not change script state.
+            stream.WriteByte(migrationVersion);
+            stream.WriteByte((byte)16);
+            this.MigrateOut(new BinaryWriter(stream));
         }
 
         /**
@@ -304,7 +210,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect)
         {
-            foreach (DetectParams d in detect)
+            foreach(DetectParams d in detect)
             {
                 XmlElement detectParamsN = GetXMLDetect(doc, d);
                 parent.AppendChild(detectParamsN);
@@ -367,7 +273,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag)
         {
-            foreach (object o in array)
+            foreach(object o in array)
             {
                 XmlElement element = GetXMLObject(doc, o, tag);
                 parent.AppendChild(element);
@@ -385,7 +291,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             XmlAttribute typ = doc.CreateAttribute("", "type", "");
             XmlElement n = doc.CreateElement("", tag, "");
 
-            if (o is LSL_List)
+            if(o is LSL_List)
             {
                 typ.Value = "list";
                 n.Attributes.Append(typ);

+ 227 - 280
OpenSim/Region/ScriptEngine/XMREngine/XMRInstCtor.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstCtor.cs

@@ -41,7 +41,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
 using OpenSim.Region.ScriptEngine.Shared;
 using OpenSim.Region.ScriptEngine.Shared.Api;
 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
+using OpenSim.Region.ScriptEngine.Yengine;
 using OpenSim.Region.Framework.Scenes;
 using log4net;
 
@@ -53,7 +53,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public partial class XMRInstance
     {
@@ -65,78 +65,82 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
         /**
          * @brief Initializer, loads script in memory and all ready for running.
-         * @param engine = XMREngine instance this is part of
+         * @param engine = YEngine instance this is part of
          * @param scriptBasePath = directory name where files are
          * @param stackSize = number of bytes to allocate for stacks
          * @param errors = return compiler errors in this array
          * @param forceRecomp = force recompile
          * Throws exception if any error, so it was successful if it returns.
          */
-        public void Initialize(XMREngine engine, string scriptBasePath,
+        public void Initialize(Yengine engine, string scriptBasePath,
                                int stackSize, int heapSize, ArrayList errors)
         {
-            if (stackSize < 16384) stackSize = 16384;
-            if (heapSize  < 16384) heapSize  = 16384;
+            if(stackSize < 16384)
+                stackSize = 16384;
+            if(heapSize < 16384)
+                heapSize = 16384;
 
-             // Save all call parameters in instance vars for easy access.
-            m_Engine         = engine;
+            // Save all call parameters in instance vars for easy access.
+            m_Engine = engine;
             m_ScriptBasePath = scriptBasePath;
-            m_StackSize      = stackSize;
-            m_HeapSize       = heapSize;
+            m_StackSize = stackSize;
+            m_StackLeft = stackSize;
+            m_HeapSize = heapSize;
             m_CompilerErrors = errors;
-            m_StateFileName  = GetStateFileName(scriptBasePath, m_ItemID);
+            m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
 
-             // Not in any XMRInstQueue.
+            // Not in any XMRInstQueue.
             m_NextInst = this;
             m_PrevInst = this;
 
-             // Set up list of API calls it has available.
-             // This also gets the API modules ready to accept setup data, such as
-             // active listeners being restored.
+            // Set up list of API calls it has available.
+            // This also gets the API modules ready to accept setup data, such as
+            // active listeners being restored.
             IScriptApi scriptApi;
             ApiManager am = new ApiManager();
-            foreach (string api in am.GetApis())
+            foreach(string api in am.GetApis())
             {
-                 // Instantiate the API for this script instance.
-                if (api != "LSL") {
+                // Instantiate the API for this script instance.
+                if(api != "LSL")
                     scriptApi = am.CreateApi(api);
-                } else {
+                else
                     scriptApi = m_XMRLSLApi = new XMRLSL_Api();
-                }
 
-                 // Connect it up to the instance.
-                InitScriptApi (engine, api, scriptApi);
+                // Connect it up to the instance.
+                InitScriptApi(engine, api, scriptApi);
             }
 
             m_XMRLSLApi.InitXMRLSLApi(this);
 
-             // Get object loaded, compiling script and reading .state file as
-             // necessary to restore the state.
+            // Get object loaded, compiling script and reading .state file as
+            // necessary to restore the state.
             suspendOnCheckRunHold = true;
             InstantiateScript();
             m_SourceCode = null;
-            if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode");
-            if (m_ObjCode.scriptEventHandlerTable == null)
-                throw new ArgumentNullException ("m_ObjCode.scriptEventHandlerTable");
+            if(m_ObjCode == null)
+                throw new ArgumentNullException("m_ObjCode");
+            if(m_ObjCode.scriptEventHandlerTable == null)
+                throw new ArgumentNullException("m_ObjCode.scriptEventHandlerTable");
 
             suspendOnCheckRunHold = false;
             suspendOnCheckRunTemp = false;
 
-             // Declare which events the script's current state can handle.
+            // Declare which events the script's current state can handle.
             int eventMask = GetStateEventFlags(stateCode);
             m_Part.SetScriptEvents(m_ItemID, eventMask);
         }
 
-        private void InitScriptApi (XMREngine engine, string api, IScriptApi scriptApi)
+        private void InitScriptApi(Yengine engine, string api, IScriptApi scriptApi)
         {
-             // Set up m_ApiManager_<APINAME> = instance pointer.
-            engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue (this, scriptApi);
+            // Set up m_ApiManager_<APINAME> = instance pointer.
+            engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue(this, scriptApi);
 
-             // Initialize the API instance.
+            // Initialize the API instance.
             scriptApi.Initialize(m_Engine, m_Part, m_Item);
-            this.InitApi (api, scriptApi);
+            this.InitApi(api, scriptApi);
         }
 
+
         /*
          * Get script object code loaded in memory and all ready to run,
          * ready to resume it from where the .state file says it was last
@@ -146,152 +150,151 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             bool compiledIt = false;
             ScriptObjCode objCode;
 
-             // If source code string is empty, use the asset ID as the object file name.
-             // Allow lines of // comments at the beginning (for such as engine selection).
+            // If source code string is empty, use the asset ID as the object file name.
+            // Allow lines of // comments at the beginning (for such as engine selection).
             int i, j, len;
-            if (m_SourceCode == null) m_SourceCode = String.Empty;
-            for (len = m_SourceCode.Length; len > 0; --len)
+            if(m_SourceCode == null)
+                m_SourceCode = String.Empty;
+            for(len = m_SourceCode.Length; len > 0; --len)
             {
-                if (m_SourceCode[len-1] > ' ')
+                if(m_SourceCode[len - 1] > ' ')
                     break;
             }
-            for (i = 0; i < len; i ++)
+            for(i = 0; i < len; i++)
             {
                 char c = m_SourceCode[i];
-                if (c <= ' ')
+                if(c <= ' ')
                     continue;
-                if (c != '/')
+                if(c != '/')
                     break;
-                if ((i + 1 >= len) || (m_SourceCode[i+1] != '/'))
+                if((i + 1 >= len) || (m_SourceCode[i + 1] != '/'))
                     break;
-                i = m_SourceCode.IndexOf ('\n', i);
-                if (i < 0)
+                i = m_SourceCode.IndexOf('\n', i);
+                if(i < 0)
                     i = len - 1;
             }
-            if ((i >= len) || !m_Engine.m_UseSourceHashCode)
+            if((i >= len) || !m_Engine.m_UseSourceHashCode)
             {
-                 // Source consists of nothing but // comments and whitespace,
-                 // or we are being forced to use the asset-id as the key, to
-                 // open an already existing object code file.
-                m_ScriptObjCodeKey = m_Item.AssetID.ToString ();
-                if (i >= len)
+                // Source consists of nothing but // comments and whitespace,
+                // or we are being forced to use the asset-id as the key, to
+                // open an already existing object code file.
+                m_ScriptObjCodeKey = m_Item.AssetID.ToString();
+                if(i >= len)
                     m_SourceCode = "";
             }
             else
             {
-                 // Make up dictionary key for the object code.
-                 // Use the same object code for identical source code
-                 // regardless of asset ID, so we don't care if they
-                 // copy scripts or not.
-                byte[] scbytes   = System.Text.Encoding.UTF8.GetBytes (m_SourceCode);
-                StringBuilder sb = new StringBuilder ((256 + 5) / 6);
-                ByteArrayToSixbitStr (sb, System.Security.Cryptography.SHA256.Create ().ComputeHash (scbytes));
-                m_ScriptObjCodeKey = sb.ToString ();
-
-                 // But source code can be just a sixbit string itself
-                 // that identifies an already existing object code file.
-                if (len - i == m_ScriptObjCodeKey.Length)
+                // Make up dictionary key for the object code.
+                // Use the same object code for identical source code
+                // regardless of asset ID, so we don't care if they
+                // copy scripts or not.
+                byte[] scbytes = System.Text.Encoding.UTF8.GetBytes(m_SourceCode);
+                StringBuilder sb = new StringBuilder((256 + 5) / 6);
+                ByteArrayToSixbitStr(sb, System.Security.Cryptography.SHA256.Create().ComputeHash(scbytes));
+                m_ScriptObjCodeKey = sb.ToString();
+
+                // But source code can be just a sixbit string itself
+                // that identifies an already existing object code file.
+                if(len - i == m_ScriptObjCodeKey.Length)
                 {
-                    for (j = len; -- j >= i;)
+                    for(j = len; --j >= i;)
                     {
-                        if (sixbit.IndexOf (m_SourceCode[j]) < 0)
+                        if(sixbit.IndexOf(m_SourceCode[j]) < 0)
                             break;
                     }
-                    if (j < i)
+                    if(j < i)
                     {
-                        m_ScriptObjCodeKey = m_SourceCode.Substring (i, len - i);
+                        m_ScriptObjCodeKey = m_SourceCode.Substring(i, len - i);
                         m_SourceCode = "";
                     }
                 }
             }
 
-             // There may already be an ScriptObjCode struct in memory that
-             // we can use.  If not, try to compile it.
-            lock (m_CompileLock)
+            // There may already be an ScriptObjCode struct in memory that
+            // we can use.  If not, try to compile it.
+            lock(m_CompileLock)
             {
-                if (!m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) || m_ForceRecomp)
+                if(!m_CompiledScriptObjCode.TryGetValue(m_ScriptObjCodeKey, out objCode) || m_ForceRecomp)
                 {
-                    objCode = TryToCompile ();
+                    objCode = TryToCompile();
                     compiledIt = true;
                 }
 
-                 // Loaded successfully, increment reference count.
+                // Loaded successfully, increment reference count.
+                // If we just compiled it though, reset count to 0 first as
+                // this is the one-and-only existance of this objCode struct,
+                // and we want any old ones for this source code to be garbage
+                // collected.
 
-                 // If we just compiled it though, reset count to 0 first as
-                 // this is the one-and-only existance of this objCode struct,
-                 // and we want any old ones for this source code to be garbage
-                 // collected.
-
-                if (compiledIt)
+                if(compiledIt)
                 {
                     m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode;
                     objCode.refCount = 0;
                 }
-                objCode.refCount ++;
+                objCode.refCount++;
 
-                 // Now set up to decrement ref count on dispose.
+                // Now set up to decrement ref count on dispose.
                 m_ObjCode = objCode;
             }
 
             try
-            {   
-                 // Fill in script instance from object code
-                 // Script instance is put in a "never-ever-has-run-before" state.
+            {
+
+                // Fill in script instance from object code
+                // Script instance is put in a "never-ever-has-run-before" state.
                 LoadObjCode();
 
-                 // Fill in script intial state
-                 // - either as loaded from a .state file
-                 // - or initial default state_entry() event
+                // Fill in script intial state
+                // - either as loaded from a .state file
+                // - or initial default state_entry() event
                 LoadInitialState();
             }
             catch
             {
-                 // If any error loading, decrement object code reference count.
-                DecObjCodeRefCount ();
+
+                // If any error loading, decrement object code reference count.
+                DecObjCodeRefCount();
                 throw;
             }
         }
 
         private const string sixbit = "0123456789_abcdefghijklmnopqrstuvwxyz@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-        private static void ByteArrayToSixbitStr (StringBuilder sb, byte[] bytes)
+        private static void ByteArrayToSixbitStr(StringBuilder sb, byte[] bytes)
         {
             int bit = 0;
             int val = 0;
-            foreach (byte b in bytes)
+            foreach(byte b in bytes)
             {
                 val |= (int)((uint)b << bit);
                 bit += 8;
-                while (bit >= 6)
+                while(bit >= 6)
                 {
-                    sb.Append (sixbit[val&63]);
+                    sb.Append(sixbit[val & 63]);
                     val >>= 6;
-                    bit  -= 6;
+                    bit -= 6;
                 }
             }
-            if (bit > 0)
-                sb.Append (sixbit[val&63]);
+            if(bit > 0)
+                sb.Append(sixbit[val & 63]);
         }
 
-        /*
-         * Try to create object code from source code
-         * If error, just throw exception
-         */
-        private ScriptObjCode TryToCompile ()
+        // 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();
+            // 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");
+            ScriptObjCode objCode = Compile();
+            if(m_CompilerErrors.Count != 0)
+                throw new Exception("compilation errors");
 
-            if (objCode == null)
-                throw new Exception ("compilation failed");
+            if(objCode == null)
+                throw new Exception("compilation failed");
 
             return objCode;
         }
@@ -299,20 +302,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /*
          * Retrieve source from asset server.
          */
-        private string FetchSource (string cameFrom)
+        private string FetchSource(string cameFrom)
         {
-            m_log.Debug ("[XMREngine]: fetching source " + cameFrom);
-            if (!cameFrom.StartsWith ("asset://"))
-                throw new Exception ("unable to retrieve source from " + cameFrom);
+            m_log.Debug("[YEngine]: fetching source " + cameFrom);
+            if(!cameFrom.StartsWith("asset://"))
+                throw new Exception("unable to retrieve source from " + cameFrom);
 
-            string assetID = cameFrom.Substring (8);
+            string assetID = cameFrom.Substring(8);
             AssetBase asset = m_Engine.World.AssetService.Get(assetID);
-            if (asset == null)
-                throw new Exception ("source not found " + cameFrom);
+            if(asset == null)
+                throw new Exception("source not found " + cameFrom);
 
-            string source = Encoding.UTF8.GetString (asset.Data);
-            if (EmptySource (source))
-                throw new Exception ("fetched source empty " + cameFrom);
+            string source = Encoding.UTF8.GetString(asset.Data);
+            if(EmptySource(source))
+                throw new Exception("fetched source empty " + cameFrom);
 
             return source;
         }
@@ -321,33 +324,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * Fill in script object initial contents.
          * Set the initial state to "default".
          */
-        private void LoadObjCode ()
+        private void LoadObjCode()
         {
-             // Script must leave this much stack remaining on calls to CheckRun().
-
+            // Script must leave this much stack remaining on calls to CheckRun().
             this.stackLimit = m_StackSize / 2;
 
-             // This is how many total heap bytes script is allowed to use.
+            // This is how many total heap bytes script is allowed to use.
             this.heapLimit = m_HeapSize;
 
-             // Allocate global variable arrays.
-            this.glblVars.AllocVarArrays (m_ObjCode.glblSizes);
+            // Allocate global variable arrays.
+            this.glblVars.AllocVarArrays(m_ObjCode.glblSizes);
 
-             // Script can handle these event codes.
+            // Script can handle these event codes.
             m_HaveEventHandlers = new bool[m_ObjCode.scriptEventHandlerTable.GetLength(1)];
-            for (int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); -- i >= 0;)
+            for(int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); --i >= 0;)
             {
-                for (int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); -- j >= 0;)
+                for(int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); --j >= 0;)
                 {
-                    if (m_ObjCode.scriptEventHandlerTable[i,j] != null)
-                     {
+                    if(m_ObjCode.scriptEventHandlerTable[i, j] != null)
+                    {
                         m_HaveEventHandlers[j] = true;
                     }
                 }
             }
-
-             // Set up microthread object which actually calls the script event handler functions.
-            this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
         }
 
         /*
@@ -360,9 +359,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private void LoadInitialState()
         {
-             // If no .state file exists, start from default state
-             // Otherwise, read initial state from the .state file
-            if (!File.Exists(m_StateFileName))
+            // If no .state file exists, start from default state
+            // Otherwise, read initial state from the .state file
+
+            if(!File.Exists(m_StateFileName))
             {
                 m_Running = true;                  // event processing is enabled
                 eventCode = ScriptEventCode.None;  // not processing any event
@@ -371,14 +371,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 doGblInit = true;
                 stateCode = 0;
 
-                PostEvent(new EventParams("state_entry", 
+                PostEvent(new EventParams("state_entry",
                                           zeroObjectArray,
                                           zeroDetectParams));
             }
             else
             {
-                FileStream fs = File.Open(m_StateFileName, 
-                                          FileMode.Open, 
+                FileStream fs = File.Open(m_StateFileName,
+                                          FileMode.Open,
                                           FileAccess.Read);
                 StreamReader ss = new StreamReader(fs);
                 string xml = ss.ReadToEnd();
@@ -390,48 +390,51 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 LoadScriptState(doc);
             }
 
-             // Post event(s) saying what caused the script to start.
-            if (m_PostOnRez)
+            /*
+             * Post event(s) saying what caused the script to start.
+             */
+            if(m_PostOnRez)
             {
                 PostEvent(new EventParams("on_rez",
-                          new Object[] { m_StartParam }, 
+                          new Object[] { m_StartParam },
                           zeroDetectParams));
             }
 
-            switch (m_StateSource)
+            switch(m_StateSource)
             {
                 case StateSource.AttachedRez:
-//                    PostEvent(new EventParams("attach",
-//                              new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() }, 
-//                              zeroDetectParams));
+                    //                    PostEvent(new EventParams("attach",
+                    //                              new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() }, 
+                    //                              zeroDetectParams));
                     break;
 
                 case StateSource.PrimCrossing:
                     PostEvent(new EventParams("changed",
-                              sbcCR, 
+                              sbcCR,
                               zeroDetectParams));
                     break;
 
+
                 case StateSource.Teleporting:
                     PostEvent(new EventParams("changed",
-                              sbcCR, 
+                              sbcCR,
                               zeroDetectParams));
                     PostEvent(new EventParams("changed",
-                              sbcCT, 
+                              sbcCT,
                               zeroDetectParams));
                     break;
 
                 case StateSource.RegionStart:
                     PostEvent(new EventParams("changed",
-                              sbcCRS, 
+                              sbcCRS,
                               zeroDetectParams));
                     break;
             }
         }
 
         private static Object[] sbcCRS = new Object[] { ScriptBaseClass.CHANGED_REGION_START };
-        private static Object[] sbcCR  = new Object[] { ScriptBaseClass.CHANGED_REGION };
-        private static Object[] sbcCT  = new Object[] { ScriptBaseClass.CHANGED_TELEPORT };
+        private static Object[] sbcCR = new Object[] { ScriptBaseClass.CHANGED_REGION };
+        private static Object[] sbcCT = new Object[] { ScriptBaseClass.CHANGED_TELEPORT };
 
         /**
          * @brief Save compilation error messages for later retrieval
@@ -439,24 +442,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private void ErrorHandler(Token token, string message)
         {
-            if (token != null)
+            if(token != null)
             {
                 string srcloc = token.SrcLoc;
-                if (srcloc.StartsWith (m_CameFrom))
-                    srcloc = srcloc.Substring (m_CameFrom.Length);
+                if(srcloc.StartsWith(m_CameFrom))
+                    srcloc = srcloc.Substring(m_CameFrom.Length);
 
                 m_CompilerErrors.Add(srcloc + " Error: " + message);
             }
-            else if (message != null)
+            else if(message != null)
                 m_CompilerErrors.Add("(0,0) Error: " + message);
-
             else
                 m_CompilerErrors.Add("(0,0) Error compiling, see exception in log");
         }
 
         /**
          * @brief Load script state from the given XML doc into the script memory
-         *  <ScriptState Engine="XMREngine" Asset=...>
+         *  <ScriptState Engine="YEngine" Asset=...>
          *      <Running>...</Running>
          *      <DoGblInit>...</DoGblInit>
          *      <Permissions granted=... mask=... />
@@ -476,25 +478,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
             // Everything we know is enclosed in <ScriptState>...</ScriptState>
             XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState");
-            if (scriptStateN == null)
+            if(scriptStateN == null)
                 throw new Exception("no <ScriptState> tag");
 
             string sen = scriptStateN.GetAttribute("Engine");
-            if ((sen == null) || (sen != m_Engine.ScriptEngineName))
-                throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute");
-
+            if((sen == null) || (sen != m_Engine.ScriptEngineName))
+                throw new Exception("<ScriptState> missing Engine=\"YEngine\" attribute");
 
             // AssetID is unique for the script source text so make sure the
             // state file was written for that source file
             string assetID = scriptStateN.GetAttribute("Asset");
-            if (assetID != m_Item.AssetID.ToString())
+            if(assetID != m_Item.AssetID.ToString())
                 throw new Exception("<ScriptState> assetID mismatch");
 
             // Also match the sourceHash in case script was
             // loaded via 'xmroption fetchsource' and has changed
-            string sourceHash = scriptStateN.GetAttribute ("SourceHash");
-            if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
-                throw new Exception ("<ScriptState> SourceHash mismatch");
+            string sourceHash = scriptStateN.GetAttribute("SourceHash");
+            if((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
+                throw new Exception("<ScriptState> SourceHash mismatch");
 
             // Get various attributes
             XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running");
@@ -519,7 +520,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin");
 
             // Script's global variables and stack contents
-            XmlElement snapshotN = (XmlElement)scriptStateN.SelectSingleNode("Snapshot");
+            XmlElement snapshotN =
+                    (XmlElement)scriptStateN.SelectSingleNode("Snapshot");
 
             Byte[] data = Convert.FromBase64String(snapshotN.InnerText);
             MemoryStream ms = new MemoryStream();
@@ -530,17 +532,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
             // Restore event queues, preserving any events that queued
             // whilst we were restoring the state
-            lock (m_QueueLock)
+            lock(m_QueueLock)
             {
                 m_DetectParams = detParams;
-                foreach (EventParams evt in m_EventQueue)
-                    eventQueue.AddLast (evt);
+                foreach(EventParams evt in m_EventQueue)
+                    eventQueue.AddLast(evt);
 
                 m_EventQueue = eventQueue;
-                for (int i = m_EventCounts.Length; -- i >= 0;)
+                for(int i = m_EventCounts.Length; --i >= 0;)
                     m_EventCounts[i] = 0;
-
-                foreach (EventParams evt in m_EventQueue)
+                foreach(EventParams evt in m_EventQueue)
                 {
                     ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
                                                                              evt.EventName);
@@ -566,17 +567,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN)
         {
             LinkedList<EventParams> eventQueue = new LinkedList<EventParams>();
-            if (eventsN != null)
+            if(eventsN != null)
             {
                 XmlNodeList eventL = eventsN.SelectNodes("Event");
-                foreach (XmlNode evnt in eventL)
+                foreach(XmlNode evnt in eventL)
                 {
-                    string name            = ((XmlElement)evnt).GetAttribute("Name");
-                    object[] parms         = ExtractXMLObjectArray(evnt, "param");
+                    string name = ((XmlElement)evnt).GetAttribute("Name");
+                    object[] parms = ExtractXMLObjectArray(evnt, "param");
                     DetectParams[] detects = RestoreDetectParams(evnt);
 
-                    if (parms   == null) parms   = zeroObjectArray;
-                    if (detects == null) detects = zeroDetectParams;
+                    if(parms == null)
+                        parms = zeroObjectArray;
+                    if(detects == null)
+                        detects = zeroDetectParams;
 
                     EventParams evt = new EventParams(name, parms, detects);
                     eventQueue.AddLast(evt);
@@ -596,38 +599,39 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         private DetectParams[] RestoreDetectParams(XmlNode detectedN)
         {
-            if (detectedN == null) return null;
+            if(detectedN == null)
+                return null;
 
             List<DetectParams> detected = new List<DetectParams>();
             XmlNodeList detectL = detectedN.SelectNodes("DetectParams");
 
             DetectParams detprm = new DetectParams();
-            foreach (XmlNode detxml in detectL)
+            foreach(XmlNode detxml in detectL)
             {
                 try
                 {
-                    detprm.Group     = new UUID(detxml.Attributes.GetNamedItem("group").Value);
-                    detprm.Key       = new UUID(detxml.Attributes.GetNamedItem("key").Value);
-                    detprm.Owner     = new UUID(detxml.Attributes.GetNamedItem("owner").Value);
+                    detprm.Group = new UUID(detxml.Attributes.GetNamedItem("group").Value);
+                    detprm.Key = new UUID(detxml.Attributes.GetNamedItem("key").Value);
+                    detprm.Owner = new UUID(detxml.Attributes.GetNamedItem("owner").Value);
 
-                    detprm.LinkNum   = Int32.Parse(detxml.Attributes.GetNamedItem("linkNum").Value);
-                    detprm.Type      = Int32.Parse(detxml.Attributes.GetNamedItem("type").Value);
+                    detprm.LinkNum = Int32.Parse(detxml.Attributes.GetNamedItem("linkNum").Value);
+                    detprm.Type = Int32.Parse(detxml.Attributes.GetNamedItem("type").Value);
 
-                    detprm.Name      = detxml.Attributes.GetNamedItem("name").Value;
+                    detprm.Name = detxml.Attributes.GetNamedItem("name").Value;
 
                     detprm.OffsetPos = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("pos").Value);
-                    detprm.Position  = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("position").Value);
-                    detprm.Velocity  = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("velocity").Value);
+                    detprm.Position = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("position").Value);
+                    detprm.Velocity = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("velocity").Value);
 
-                    detprm.Rotation  = new LSL_Types.Quaternion(detxml.Attributes.GetNamedItem("rotation").Value);
+                    detprm.Rotation = new LSL_Types.Quaternion(detxml.Attributes.GetNamedItem("rotation").Value);
 
                     detected.Add(detprm);
                     detprm = new DetectParams();
                 }
-                catch (Exception e)
+                catch(Exception e)
                 {
-                    m_log.Warn("[XMREngine]: RestoreDetectParams bad XML: " + detxml.ToString());
-                    m_log.Warn("[XMREngine]: ... " + e.ToString());
+                    m_log.Warn("[YEngine]: RestoreDetectParams bad XML: " + detxml.ToString());
+                    m_log.Warn("[YEngine]: ... " + e.ToString());
                 }
             }
 
@@ -646,8 +650,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             List<Object> olist = new List<Object>();
 
             XmlNodeList itemL = parent.SelectNodes(tag);
-            foreach (XmlNode item in itemL)
+            foreach(XmlNode item in itemL)
+            {
                 olist.Add(ExtractXMLObjectValue(item));
+            }
 
             return olist.ToArray();
         }
@@ -656,10 +662,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         {
             string itemType = item.Attributes.GetNamedItem("type").Value;
 
-            if (itemType == "list")
+            if(itemType == "list")
+            {
                 return new LSL_List(ExtractXMLObjectArray(item, "item"));
+            }
 
-            if (itemType == "OpenMetaverse.UUID")
+            if(itemType == "OpenMetaverse.UUID")
             {
                 UUID val = new UUID();
                 UUID.TryParse(item.InnerText, out val);
@@ -667,15 +675,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             }
 
             Type itemT = Type.GetType(itemType);
-            if (itemT == null)
+            if(itemT == null)
             {
                 Object[] args = new Object[] { item.InnerText };
 
                 string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared";
                 itemT = Type.GetType(assembly);
-                if (itemT == null)
+                if(itemT == null)
+                {
                     return null;
-
+                }
                 return Activator.CreateInstance(itemT, args);
             }
 
@@ -688,89 +697,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * Input:
          *  stream = as generated by MigrateOutEventHandler()
          */
-        private void MigrateInEventHandler (Stream stream)
-        {
-            miehexcep = null;
-
-            // do all the work in the MigrateInEventHandlerThread() method below
-            miehstream = stream;
-
-            XMRScriptThread cst = m_Engine.CurrentScriptThread ();
-            if (cst != null)
-            {
-                // in case we are getting called inside some LSL Api function
-                MigrateInEventHandlerThread ();
-            }
-            else
-            {
-                // some other thread, do migration via a script thread
-                m_Engine.QueueToTrunk(this.MigrateInEventHandlerThread);
-
-                // wait for it to complete
-                lock (miehdone)
-                {
-                    while (miehstream != null)
-                        Monitor.Wait(miehdone);
-                }
-            }
-
-            // maybe it threw up
-            if (miehexcep != null)
-                throw miehexcep;
-        }
-
-        private Exception miehexcep;
-        private object miehdone = new object ();
-        private Stream miehstream;
-        private void MigrateInEventHandlerThread ()
+        private void MigrateInEventHandler(Stream stream)
         {
-            try
+            int mv = stream.ReadByte();
+            if(mv != migrationVersion)
+                throw new Exception("incoming migration version " + mv + " but accept only " + migrationVersion);
+
+            stream.ReadByte();  // ignored
+
+            /*
+             * Restore script variables and stack and other state from stream.
+             * And it also marks us busy (by setting this.eventCode) so we can't be
+             * started again and this event lost.  If it restores this.eventCode =
+             * None, the the script was idle.
+             */
+            lock(m_RunLock)
             {
-                int mv = miehstream.ReadByte ();
-                if (mv != migrationVersion)
-                    throw new Exception ("incoming migration version " + mv + " but accept only " + migrationVersion);
-
-                miehstream.ReadByte ();  // ignored
-
-                 // Restore script variables and stack and other state from stream.
-                 // And it also marks us busy (by setting this.eventCode) so we can't be
-                 // started again and this event lost.
-
-                BinaryReader br = new BinaryReader (miehstream);
-                this.MigrateIn (br);
+                BinaryReader br = new BinaryReader(stream);
+                this.MigrateIn(br);
 
-                 // If eventCode is None, it means the script was idle when migrated.
-
-                if (this.eventCode != ScriptEventCode.None)
-                {
-                     // So microthread.Start() calls XMRScriptUThread.Main() which calls the
-                     // event handler function.  The event handler function sees the stack
-                     // frames in this.stackFrames and restores its args and locals, then calls
-                     // whatever it was calling when the snapshot was taken.  That function also
-                     // sees this.stackFrames and restores its args and locals, and so on...
-                     // Eventually it gets to the point of calling CheckRun() which sees we are
-                     // doing a restore and it suspends, returning here with the microthread
-                     // stack all restored.  It shouldn't ever throw an exception.
-
-                    this.stackFramesRestored = false;
-                    Exception te = microthread.StartEx ();
-                    if (te != null) throw te;
-                    if (!this.stackFramesRestored)
-                        throw new Exception ("migrate in did not complete");
-                }
-            }
-            catch (Exception e)
-            {
-                miehexcep = e;
-            }
-            finally
-            {
-                 // Wake the MigrateInEventHandler() method above.
-                lock (miehdone)
-                {
-                    miehstream = null;
-                    Monitor.Pulse (miehdone);
-                }
+                m_RunOnePhase = "MigrateInEventHandler finished";
+                CheckRunLockInvariants(true);
             }
         }
     }

+ 31 - 43
OpenSim/Region/ScriptEngine/XMREngine/XMRInstMain.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstMain.cs

@@ -41,7 +41,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
 using OpenSim.Region.ScriptEngine.Shared;
 using OpenSim.Region.ScriptEngine.Shared.Api;
 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
+using OpenSim.Region.ScriptEngine.Yengine;
 using OpenSim.Region.Framework.Scenes;
 using log4net;
 
@@ -55,7 +55,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
 // This class exists in the main app domain
 //
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /**
      * @brief Which queue it is in as far as running is concerned,
@@ -75,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
      *   SUSPENDED->ONSTARTQ              : by any thread (NOT YET IMPLEMENTED, should be under some kind of lock?)
      *   RESETTING->ONSTARTQ              : only by the thread that transitioned it to RESETTING
      */
-    public enum XMRInstState {
+    public enum XMRInstState
+    {
         CONSTRUCT,     // it is being constructed
         IDLE,          // nothing happening (finished last event and m_EventQueue is empty)
         ONSTARTQ,      // inserted on m_Engine.m_StartQueue
@@ -89,7 +90,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         DISPOSED       // has been disposed
     }
 
-    public partial class XMRInstance : XMRInstAbstract, IDisposable
+    public partial class XMRInstance: XMRInstAbstract, IDisposable
     {
         /******************************************************************\
          *  This module contains the instance variables for XMRInstance.  *
@@ -103,44 +104,45 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public static readonly ILog m_log =
             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
+        public XMRInstance m_NextInst;  // used by XMRInstQueue
+        public XMRInstance m_PrevInst;
+
         // For a given m_Item.AssetID, do we have the compiled object code and where
         // is it?
         public static object m_CompileLock = new object();
-        private static Dictionary<string,ScriptObjCode> m_CompiledScriptObjCode = new Dictionary<string,ScriptObjCode>();
-
-        public  XMRInstance  m_NextInst;  // used by XMRInstQueue
-        public  XMRInstance  m_PrevInst;
-        public  XMRInstState m_IState;
-
-        public  bool m_ForceRecomp = false;
-        public  SceneObjectPart m_Part = null;
-        public  uint m_LocalID = 0;
-        public  TaskInventoryItem m_Item = null;
-        public  UUID m_ItemID;
-        public  UUID m_PartUUID;
+        private static Dictionary<string, ScriptObjCode> m_CompiledScriptObjCode = new Dictionary<string, ScriptObjCode>();
+
+        public XMRInstState m_IState;
+
+        public bool m_ForceRecomp = false;
+        public SceneObjectPart m_Part = null;
+        public uint m_LocalID = 0;
+        public TaskInventoryItem m_Item = null;
+        public UUID m_ItemID;
+        public UUID m_PartUUID;
         private string m_CameFrom;
         private string m_ScriptObjCodeKey;
 
-        private XMREngine m_Engine = null;
+        private Yengine m_Engine = null;
         private string m_ScriptBasePath;
         private string m_StateFileName;
-        public  string m_SourceCode;
-        public  bool m_PostOnRez;
+        public string m_SourceCode;
+        public bool m_PostOnRez;
         private DetectParams[] m_DetectParams = null;
-        public  int m_StartParam = 0;
-        public  StateSource m_StateSource;
-        public  string m_DescName;
+        public int m_StartParam = 0;
+        public StateSource m_StateSource;
+        public string m_DescName;
         private bool[] m_HaveEventHandlers;
-        public  int m_StackSize;
-        public  int m_HeapSize;
+        public int m_StackSize;
+        public int m_HeapSize;
         private ArrayList m_CompilerErrors;
         private DateTime m_LastRanAt = DateTime.MinValue;
         private string m_RunOnePhase = "hasn't run";
         private string m_CheckRunPhase = "hasn't checked";
-        public  int m_InstEHEvent  = 0;  // number of events dequeued (StartEventHandler called)
-        public  int m_InstEHSlice  = 0;  // number of times handler timesliced (ResumeEx called)
-        public  double m_CPUTime   = 0;  // accumulated CPU time (milliseconds)
-        public  double m_SliceStart = 0;  // when did current exec start
+        public int m_InstEHEvent = 0;  // number of events dequeued (StartEventHandler called)
+        public int m_InstEHSlice = 0;  // number of times handler timesliced (ResumeEx called)
+        public double m_CPUTime = 0;  // accumulated CPU time (milliseconds)
+        public double m_SliceStart = 0;  // when did current exec start
 
         // If code needs to have both m_QueueLock and m_RunLock,
         // be sure to lock m_RunLock first then m_QueueLock, as
@@ -156,7 +158,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public bool m_Running = true;
 
         // queue of events that haven't been acted upon yet
-        public LinkedList<EventParams> m_EventQueue = new LinkedList<EventParams> ();
+        public LinkedList<EventParams> m_EventQueue = new LinkedList<EventParams>();
 
         // number of events of each code currently in m_EventQueue.
         private int[] m_EventCounts = new int[(int)ScriptEventCode.Size];
@@ -175,20 +177,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
 
         private XMRLSL_Api m_XMRLSLApi;
 
-        /*
-         * We will use this microthread to run the scripts event handlers.
-         */
-        private IScriptUThread microthread;
-
-        /*
-         * Set to perform migration.
-         */
-        public bool stackFramesRestored; // set true by CheckRun() when stack has been 
-                                         // restored and is about to suspend the microthread
-        public bool captureStackFrames;  // set true to tell CheckRun() to throw a
-                                         // StackCaptureException() causing it to capture a
-                                         // snapshot of the script's stack
-
         /*
          * Makes sure migration data version is same on both ends.
          */

+ 133 - 104
OpenSim/Region/ScriptEngine/XMREngine/XMRInstMisc.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs

@@ -42,7 +42,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
 using OpenSim.Region.ScriptEngine.Shared;
 using OpenSim.Region.ScriptEngine.Shared.Api;
 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
-using OpenSim.Region.ScriptEngine.XMREngine;
+using OpenSim.Region.ScriptEngine.Yengine;
 using OpenSim.Region.Framework.Scenes;
 using log4net;
 
@@ -56,7 +56,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
 // This class exists in the main app domain
 //
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public partial class XMRInstance
     {
@@ -80,57 +80,48 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             suspendOnCheckRunHold = true;
 
             /*
-             * Wait for it to stop executing and prevent it from starting again
-             * as it can't run without a microthread.
+             * Don't send us any more events.
              */
-            lock (m_RunLock)
+            lock(m_RunLock)
             {
-                if (microthread != null)
+                if(m_Part != null)
                 {
-                    m_RunOnePhase = "disposing";
-                    CheckRunLockInvariants(true);
-                    microthread.Dispose ();
-                    microthread = null;
+                    m_Part.RemoveScriptEvents(m_ItemID);
+                    AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
+                    m_Part = null;
                 }
             }
 
-            /*
-             * Don't send us any more events.
-             */
-            if (m_Part != null)
-            {
-                xmrTrapRegionCrossing (0);
-                m_Part.RemoveScriptEvents(m_ItemID);
-                AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
-                m_Part = null;
-            }
-
             /*
              * Let script methods get garbage collected if no one else is using
              * them.
              */
-            DecObjCodeRefCount ();
+            DecObjCodeRefCount();
         }
 
-        private void DecObjCodeRefCount ()
+        private void DecObjCodeRefCount()
         {
-            if (m_ObjCode != null) {
-                lock (m_CompileLock) {
+            if(m_ObjCode != null)
+            {
+                lock(m_CompileLock)
+                {
                     ScriptObjCode objCode;
 
-                    if (m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) &&
+                    if(m_CompiledScriptObjCode.TryGetValue(m_ScriptObjCodeKey, out objCode) &&
                         (objCode == m_ObjCode) &&
-                        (-- objCode.refCount == 0)) {
-                        m_CompiledScriptObjCode.Remove (m_ScriptObjCodeKey);
+                        (--objCode.refCount == 0))
+                    {
+                        m_CompiledScriptObjCode.Remove(m_ScriptObjCodeKey);
                     }
                 }
                 m_ObjCode = null;
             }
         }
 
-        public void Verbose (string format, params object[] args)
+        public void Verbose(string format, params object[] args)
         {
-            if (m_Engine.m_Verbose) m_log.DebugFormat (format, args);
+            if(m_Engine.m_Verbose)
+                m_log.DebugFormat(format, args);
         }
 
         // Called by 'xmr top' console command
@@ -138,37 +129,39 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         //  Sacha 
         public void RunTestTop()
         {
-          if (m_InstEHSlice > 0){
-            Console.WriteLine(m_DescName);
-            Console.WriteLine("    m_LocalID       = " + m_LocalID);
-            Console.WriteLine("    m_ItemID        = " + m_ItemID);
-            Console.WriteLine("    m_Item.AssetID  = " + m_Item.AssetID);
-            Console.WriteLine("    m_StartParam    = " + m_StartParam);
-            Console.WriteLine("    m_PostOnRez     = " + m_PostOnRez);
-            Console.WriteLine("    m_StateSource   = " + m_StateSource);
-            Console.WriteLine("    m_SuspendCount  = " + m_SuspendCount);
-            Console.WriteLine("    m_SleepUntil    = " + m_SleepUntil);
-            Console.WriteLine("    m_IState        = " + m_IState.ToString());
-            Console.WriteLine("    m_StateCode     = " + GetStateName(stateCode));
-            Console.WriteLine("    eventCode       = " + eventCode.ToString());
-            Console.WriteLine("    m_LastRanAt     = " + m_LastRanAt.ToString());
-            Console.WriteLine("    heapUsed/Limit  = " + xmrHeapUsed () + "/" + heapLimit);
-            Console.WriteLine("    m_InstEHEvent   = " + m_InstEHEvent.ToString());
-            Console.WriteLine("    m_InstEHSlice   = " + m_InstEHSlice.ToString());
-          }
+            if(m_InstEHSlice > 0)
+            {
+                Console.WriteLine(m_DescName);
+                Console.WriteLine("    m_LocalID       = " + m_LocalID);
+                Console.WriteLine("    m_ItemID        = " + m_ItemID);
+                Console.WriteLine("    m_Item.AssetID  = " + m_Item.AssetID);
+                Console.WriteLine("    m_StartParam    = " + m_StartParam);
+                Console.WriteLine("    m_PostOnRez     = " + m_PostOnRez);
+                Console.WriteLine("    m_StateSource   = " + m_StateSource);
+                Console.WriteLine("    m_SuspendCount  = " + m_SuspendCount);
+                Console.WriteLine("    m_SleepUntil    = " + m_SleepUntil);
+                Console.WriteLine("    m_IState        = " + m_IState.ToString());
+                Console.WriteLine("    m_StateCode     = " + GetStateName(stateCode));
+                Console.WriteLine("    eventCode       = " + eventCode.ToString());
+                Console.WriteLine("    m_LastRanAt     = " + m_LastRanAt.ToString());
+                Console.WriteLine("    heapUsed/Limit  = " + xmrHeapUsed() + "/" + heapLimit);
+                Console.WriteLine("    m_InstEHEvent   = " + m_InstEHEvent.ToString());
+                Console.WriteLine("    m_InstEHSlice   = " + m_InstEHSlice.ToString());
+            }
         }
 
         // Called by 'xmr ls' console command
         // to dump this script's state to console
         public string RunTestLs(bool flagFull)
         {
-            if (flagFull) {
+            if(flagFull)
+            {
                 StringBuilder sb = new StringBuilder();
                 sb.AppendLine(m_DescName);
                 sb.AppendLine("    m_LocalID            = " + m_LocalID);
-                sb.AppendLine("    m_ItemID             = " + m_ItemID  + "  (.state file)");
+                sb.AppendLine("    m_ItemID             = " + m_ItemID + "  (.state file)");
                 sb.AppendLine("    m_Item.AssetID       = " + m_Item.AssetID);
-                sb.AppendLine("    m_Part.WorldPosition = " + m_Part.GetWorldPosition ());
+                sb.AppendLine("    m_Part.WorldPosition = " + m_Part.GetWorldPosition());
                 sb.AppendLine("    m_ScriptObjCodeKey   = " + m_ScriptObjCodeKey + "  (source text)");
                 sb.AppendLine("    m_StartParam         = " + m_StartParam);
                 sb.AppendLine("    m_PostOnRez          = " + m_PostOnRez);
@@ -185,28 +178,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                 sb.AppendLine("    suspOnCkRunHold      = " + suspendOnCheckRunHold);
                 sb.AppendLine("    suspOnCkRunTemp      = " + suspendOnCheckRunTemp);
                 sb.AppendLine("    m_CheckRunPhase      = " + m_CheckRunPhase);
-                sb.AppendLine("    heapUsed/Limit       = " + xmrHeapUsed () + "/" + heapLimit);
+                sb.AppendLine("    heapUsed/Limit       = " + xmrHeapUsed() + "/" + heapLimit);
                 sb.AppendLine("    m_InstEHEvent        = " + m_InstEHEvent.ToString());
                 sb.AppendLine("    m_InstEHSlice        = " + m_InstEHSlice.ToString());
                 sb.AppendLine("    m_CPUTime            = " + m_CPUTime);
                 sb.AppendLine("    callMode             = " + callMode);
-                sb.AppendLine("    captureStackFrames   = " + captureStackFrames);
-                sb.AppendLine("    stackFramesRestored  = " + stackFramesRestored);
-                lock (m_QueueLock)
+                lock(m_QueueLock)
                 {
                     sb.AppendLine("    m_Running            = " + m_Running);
-                    foreach (EventParams evt in m_EventQueue)
+                    foreach(EventParams evt in m_EventQueue)
                     {
                         sb.AppendLine("        evt.EventName        = " + evt.EventName);
                     }
                 }
                 return sb.ToString();
-            } else {
-                return String.Format("{0} {1} {2} {3} {4} {5}", 
-                        m_ItemID, 
-                        m_CPUTime.ToString("F3").PadLeft(9), 
-                        m_InstEHEvent.ToString().PadLeft(9), 
-                        m_IState.ToString().PadRight(10), 
+            }
+            else
+            {
+                return String.Format("{0} {1} {2} {3} {4} {5}",
+                        m_ItemID,
+                        m_CPUTime.ToString("F3").PadLeft(9),
+                        m_InstEHEvent.ToString().PadLeft(9),
+                        m_IState.ToString().PadRight(10),
                         m_Part.GetWorldPosition().ToString().PadRight(32),
                         m_DescName);
             }
@@ -218,16 +211,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public int GetStateEventFlags(int stateCode)
         {
-            if ((stateCode < 0) ||
+            if((stateCode < 0) ||
                 (stateCode >= m_ObjCode.scriptEventHandlerTable.GetLength(0)))
             {
                 return 0;
             }
 
             int code = 0;
-            for (int i = 0 ; i < 32; i ++)
+            for(int i = 0; i < 32; i++)
             {
-                if (m_ObjCode.scriptEventHandlerTable[stateCode, i] != null)
+                if(m_ObjCode.scriptEventHandlerTable[stateCode, i] != null)
                 {
                     code |= 1 << i;
                 }
@@ -239,41 +232,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Get the .state file name.
          */
-        public static string GetStateFileName (string scriptBasePath, UUID itemID)
+        public static string GetStateFileName(string scriptBasePath, UUID itemID)
         {
-            return GetScriptFileName (scriptBasePath, itemID.ToString() + ".state");
+            return GetScriptFileName(scriptBasePath, itemID.ToString() + ".state");
         }
 
-        public string GetScriptFileName (string filename)
+        public string GetScriptFileName(string filename)
         {
-            return GetScriptFileName (m_ScriptBasePath, filename);
+            return GetScriptFileName(m_ScriptBasePath, filename);
         }
 
-        public static string GetScriptFileName (string scriptBasePath, string filename)
+        public static string GetScriptFileName(string scriptBasePath, string filename)
         {
             /*
              * Get old path, ie, all files lumped in a single huge directory.
              */
-            string oldPath = Path.Combine (scriptBasePath, filename);
+            string oldPath = Path.Combine(scriptBasePath, filename);
 
             /*
              * Get new path, ie, files split up based on first 2 chars of name.
              */
-            string subdir = filename.Substring (0, 2);
-            filename = filename.Substring (2);
-            scriptBasePath = Path.Combine (scriptBasePath, subdir);
-            Directory.CreateDirectory (scriptBasePath);
-            string newPath = Path.Combine (scriptBasePath, filename);
+            //           string subdir = filename.Substring (0, 2);
+            //           filename = filename.Substring (2);
+            string subdir = filename.Substring(0, 1);
+            filename = filename.Substring(1);
+            scriptBasePath = Path.Combine(scriptBasePath, subdir);
+            Directory.CreateDirectory(scriptBasePath);
+            string newPath = Path.Combine(scriptBasePath, filename);
 
             /*
              * If file exists only in old location, move to new location.
              * If file exists in both locations, delete old location.
              */
-            if (File.Exists (oldPath)) {
-                if (File.Exists (newPath)) {
-                    File.Delete (oldPath);
-                } else {
-                    File.Move (oldPath, newPath);
+            if(File.Exists(oldPath))
+            {
+                if(File.Exists(newPath))
+                {
+                    File.Delete(oldPath);
+                }
+                else
+                {
+                    File.Move(oldPath, newPath);
                 }
             }
 
@@ -286,12 +285,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Decode state code (int) to state name (string).
          */
-        public string GetStateName (int stateCode)
+        public string GetStateName(int stateCode)
         {
-            try {
+            try
+            {
                 return m_ObjCode.stateNames[stateCode];
-            } catch {
-                return stateCode.ToString ();
+            }
+            catch
+            {
+                return stateCode.ToString();
             }
         }
 
@@ -300,42 +302,66 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public int StartParam
         {
-            get { return m_StartParam; }
-            set { m_StartParam = value; }
+            get
+            {
+                return m_StartParam;
+            }
+            set
+            {
+                m_StartParam = value;
+            }
         }
 
         public SceneObjectPart SceneObject
         {
-            get { return m_Part; }
+            get
+            {
+                return m_Part;
+            }
         }
 
         public DetectParams[] DetectParams
         {
-            get { return m_DetectParams; }
-            set { m_DetectParams = value; }
+            get
+            {
+                return m_DetectParams;
+            }
+            set
+            {
+                m_DetectParams = value;
+            }
         }
 
         public UUID ItemID
         {
-            get { return m_ItemID; }
+            get
+            {
+                return m_ItemID;
+            }
         }
 
         public UUID AssetID
         {
-            get { return m_Item.AssetID; }
+            get
+            {
+                return m_Item.AssetID;
+            }
         }
 
         public bool Running
         {
-            get { return m_Running; }
+            get
+            {
+                return m_Running;
+            }
             set
             {
-                lock (m_QueueLock)
+                lock(m_QueueLock)
                 {
                     m_Running = value;
-                    if (!value)
+                    if(!value)
                     {
-                        EmptyEventQueues ();
+                        EmptyEventQueues();
                     }
                 }
             }
@@ -345,26 +371,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @brief Empty out the event queues.
          *        Assumes caller has the m_QueueLock locked.
          */
-        public void EmptyEventQueues ()
+        public void EmptyEventQueues()
         {
             m_EventQueue.Clear();
-            for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0;
+            for(int i = m_EventCounts.Length; --i >= 0;)
+                m_EventCounts[i] = 0;
         }
 
         /**
          * @brief Convert an LSL vector to an Openmetaverse vector.
          */
-        public static OpenMetaverse.Vector3 LSLVec2OMVec (LSL_Vector lslVec)
+        public static OpenMetaverse.Vector3 LSLVec2OMVec(LSL_Vector lslVec)
         {
-            return new OpenMetaverse.Vector3 ((float)lslVec.x, (float)lslVec.y, (float)lslVec.z);
+            return new OpenMetaverse.Vector3((float)lslVec.x, (float)lslVec.y, (float)lslVec.z);
         }
 
         /**
          * @brief Extract an integer from an element of an LSL_List.
          */
-        public static int ListInt (object element)
+        public static int ListInt(object element)
         {
-            if (element is LSL_Integer) {
+            if(element is LSL_Integer)
+            {
                 return (int)(LSL_Integer)element;
             }
             return (int)element;
@@ -373,9 +401,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Extract a string from an element of an LSL_List.
          */
-        public static string ListStr (object element)
+        public static string ListStr(object element)
         {
-            if (element is LSL_String) {
+            if(element is LSL_String)
+            {
                 return (string)(LSL_String)element;
             }
             return (string)element;

+ 44 - 38
OpenSim/Region/ScriptEngine/XMREngine/XMRInstQueue.cs → OpenSim/Region/ScriptEngine/YEngine/XMRInstQueue.cs

@@ -27,7 +27,7 @@
 
 using System;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     /**
      * @brief Implements a queue of XMRInstance's.
@@ -47,15 +47,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public void InsertHead(XMRInstance inst)
         {
-            if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) {
+            if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
                 throw new Exception("already in list");
-            }
+
             inst.m_PrevInst = null;
-            if ((inst.m_NextInst = m_Head) == null) {
+            if((inst.m_NextInst = m_Head) == null)
                 m_Tail = inst;
-            } else {
+            else
                 m_Head.m_PrevInst = inst;
-            }
+
             m_Head = inst;
         }
 
@@ -65,15 +65,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public void InsertTail(XMRInstance inst)
         {
-            if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) {
+            if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
                 throw new Exception("already in list");
-            }
+
             inst.m_NextInst = null;
-            if ((inst.m_PrevInst = m_Tail) == null) {
+            if((inst.m_PrevInst = m_Tail) == null)
                 m_Head = inst;
-            } else {
+            else
                 m_Tail.m_NextInst = inst;
-            }
+
             m_Tail = inst;
         }
 
@@ -84,19 +84,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          */
         public void InsertBefore(XMRInstance inst, XMRInstance after)
         {
-            if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) {
+            if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
                 throw new Exception("already in list");
-            }
-            if (after == null) {
+
+            if(after == null)
                 InsertTail(inst);
-            } else {
+            else
+            {
                 inst.m_NextInst = after;
                 inst.m_PrevInst = after.m_PrevInst;
-                if (inst.m_PrevInst == null) {
+                if(inst.m_PrevInst == null)
                     m_Head = inst;
-                } else {
+                else
                     inst.m_PrevInst.m_NextInst = inst;
-                }
                 after.m_PrevInst = inst;
             }
         }
@@ -119,12 +119,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public XMRInstance RemoveHead()
         {
             XMRInstance inst = m_Head;
-            if (inst != null) {
-                if ((m_Head = inst.m_NextInst) == null) {
+            if(inst != null)
+            {
+                if((m_Head = inst.m_NextInst) == null)
                     m_Tail = null;
-                } else {
+                else
                     m_Head.m_PrevInst = null;
-                }
+
                 inst.m_NextInst = inst;
                 inst.m_PrevInst = inst;
             }
@@ -139,12 +140,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         public XMRInstance RemoveTail()
         {
             XMRInstance inst = m_Tail;
-            if (inst != null) {
-                if ((m_Tail = inst.m_PrevInst) == null) {
+            if(inst != null)
+            {
+                if((m_Tail = inst.m_PrevInst) == null)
                     m_Head = null;
-                } else {
+                else
                     m_Tail.m_NextInst = null;
-                }
+
                 inst.m_NextInst = inst;
                 inst.m_PrevInst = inst;
             }
@@ -160,25 +162,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         {
             XMRInstance next = inst.m_NextInst;
             XMRInstance prev = inst.m_PrevInst;
-            if ((prev == inst) || (next == inst)) {
+            if((prev == inst) || (next == inst))
                 throw new Exception("not in a list");
-            }
-            if (next == null) {
-                if (m_Tail != inst) {
+
+            if(next == null)
+            {
+                if(m_Tail != inst)
                     throw new Exception("not in this list");
-                }
+
                 m_Tail = prev;
-            } else {
-                next.m_PrevInst = prev;
             }
-            if (prev == null) {
-                if (m_Head != inst) {
+            else
+                next.m_PrevInst = prev;
+
+            if(prev == null)
+            {
+                if(m_Head != inst)
                     throw new Exception("not in this list");
-                }
+
                 m_Head = next;
-            } else {
-                prev.m_NextInst = next;
             }
+            else
+                prev.m_NextInst = next;
+
             inst.m_NextInst = inst;
             inst.m_PrevInst = inst;
         }

File diff suppressed because it is too large
+ 238 - 250
OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs


+ 6296 - 0
OpenSim/Region/ScriptEngine/YEngine/XMRObjectTokens.cs

@@ -0,0 +1,6296 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
+using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
+using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
+using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
+using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
+using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
+
+/**
+ * Contains classes that disassemble or decompile an xmrobj file.
+ * See xmrengcomp.cx utility program.
+ */
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    /*
+     * Encapsulate object code for a method.
+     */
+    public abstract class ObjectTokens
+    {
+        public ScriptObjCode scriptObjCode;
+
+        public ObjectTokens(ScriptObjCode scriptObjCode)
+        {
+            this.scriptObjCode = scriptObjCode;
+        }
+
+        public abstract void Close();
+        public abstract void BegMethod(DynamicMethod method);
+        public abstract void EndMethod();
+        public abstract void DefineLabel(int number, string name);
+        public abstract void DefineLocal(int number, string name, string type, Type syType);
+        public abstract void DefineMethod(string methName, Type retType, Type[] argTypes, string[] argNames);
+        public abstract void MarkLabel(int offset, int number);
+        public abstract void BegExcBlk(int offset);
+        public abstract void BegCatBlk(int offset, Type excType);
+        public abstract void BegFinBlk(int offset);
+        public abstract void EndExcBlk(int offset);
+        public abstract void EmitNull(int offset, OpCode opCode);
+        public abstract void EmitField(int offset, OpCode opCode, FieldInfo field);
+        public abstract void EmitLocal(int offset, OpCode opCode, int number);
+        public abstract void EmitType(int offset, OpCode opCode, Type type);
+        public abstract void EmitLabel(int offset, OpCode opCode, int number);
+        public abstract void EmitLabels(int offset, OpCode opCode, int[] numbers);
+        public abstract void EmitMethod(int offset, OpCode opCode, MethodInfo method);
+        public abstract void EmitCtor(int offset, OpCode opCode, ConstructorInfo ctor);
+        public abstract void EmitDouble(int offset, OpCode opCode, double value);
+        public abstract void EmitFloat(int offset, OpCode opCode, float value);
+        public abstract void EmitInteger(int offset, OpCode opCode, int value);
+        public abstract void EmitString(int offset, OpCode opCode, string value);
+    }
+
+    /******************\
+     *  DISASSEMBLER  *
+    \******************/
+
+    public class OTDisassemble: ObjectTokens
+    {
+        private static readonly int OPCSTRWIDTH = 12;
+
+        private Dictionary<int, string> labelNames;
+        private Dictionary<int, string> localNames;
+        private StringBuilder lbuf = new StringBuilder();
+        private TextWriter twout;
+
+        public OTDisassemble(ScriptObjCode scriptObjCode, TextWriter twout) : base(scriptObjCode)
+        {
+            this.twout = twout;
+        }
+
+        public override void Close()
+        {
+            twout.WriteLine("TheEnd.");
+        }
+
+        /**
+         * About to generate object code for this method.
+         */
+        public override void BegMethod(DynamicMethod method)
+        {
+            labelNames = new Dictionary<int, string>();
+            localNames = new Dictionary<int, string>();
+
+            twout.WriteLine("");
+
+            lbuf.Append(method.ReturnType.Name);
+            lbuf.Append(' ');
+            lbuf.Append(method.Name);
+
+            ParameterInfo[] parms = method.GetParameters();
+            int nArgs = parms.Length;
+            lbuf.Append(" (");
+            for(int i = 0; i < nArgs; i++)
+            {
+                if(i > 0)
+                    lbuf.Append(", ");
+                lbuf.Append(parms[i].ParameterType.Name);
+            }
+            lbuf.Append(')');
+            FlushLine();
+
+            lbuf.Append('{');
+            FlushLine();
+        }
+
+        /**
+         * Dump out reconstructed source for this method.
+         */
+        public override void EndMethod()
+        {
+            lbuf.Append('}');
+            FlushLine();
+        }
+
+        /**
+         * Add instructions to stream.
+         */
+        public override void DefineLabel(int number, string name)
+        {
+            labelNames[number] = name + "$" + number;
+        }
+
+        public override void DefineLocal(int number, string name, string type, Type syType)
+        {
+            localNames[number] = name + "$" + number;
+
+            lbuf.Append("          ");
+            lbuf.Append(type.PadRight(OPCSTRWIDTH - 1));
+            lbuf.Append(' ');
+            lbuf.Append(localNames[number]);
+            FlushLine();
+        }
+
+        public override void DefineMethod(string methName, Type retType, Type[] argTypes, string[] argNames)
+        {
+        }
+
+        public override void MarkLabel(int offset, int number)
+        {
+            LinePrefix(offset);
+            lbuf.Append(labelNames[number]);
+            lbuf.Append(":");
+            FlushLine();
+        }
+
+        public override void BegExcBlk(int offset)
+        {
+            LinePrefix(offset);
+            lbuf.Append(" BeginExceptionBlock");
+            FlushLine();
+        }
+
+        public override void BegCatBlk(int offset, Type excType)
+        {
+            LinePrefix(offset);
+            lbuf.Append(" BeginCatchBlock ");
+            lbuf.Append(excType.Name);
+            FlushLine();
+        }
+
+        public override void BegFinBlk(int offset)
+        {
+            LinePrefix(offset);
+            lbuf.Append(" BeginFinallyBlock");
+            FlushLine();
+        }
+
+        public override void EndExcBlk(int offset)
+        {
+            LinePrefix(offset);
+            lbuf.Append(" EndExceptionBlock");
+            FlushLine();
+        }
+
+        public override void EmitNull(int offset, OpCode opCode)
+        {
+            LinePrefix(offset, opCode);
+            FlushLine();
+        }
+
+        public override void EmitField(int offset, OpCode opCode, FieldInfo field)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(field.DeclaringType.Name);
+            lbuf.Append(':');
+            lbuf.Append(field.Name);
+            lbuf.Append(" -> ");
+            lbuf.Append(field.FieldType.Name);
+            lbuf.Append("   (field)");
+            FlushLine();
+        }
+
+        public override void EmitLocal(int offset, OpCode opCode, int number)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(localNames[number]);
+            lbuf.Append("   (local)");
+            FlushLine();
+        }
+
+        public override void EmitType(int offset, OpCode opCode, Type type)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(type.Name);
+            lbuf.Append("   (type)");
+            FlushLine();
+        }
+
+        public override void EmitLabel(int offset, OpCode opCode, int number)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(labelNames[number]);
+            lbuf.Append("   (label)");
+            FlushLine();
+        }
+
+        public override void EmitLabels(int offset, OpCode opCode, int[] numbers)
+        {
+            LinePrefix(offset, opCode);
+
+            int lineLen = lbuf.Length;
+            int nLabels = numbers.Length;
+            for(int i = 0; i < nLabels; i++)
+            {
+                if(i > 0)
+                {
+                    lbuf.AppendLine();
+                    lbuf.Append(",".PadLeft(lineLen));
+                }
+                lbuf.Append(labelNames[numbers[i]]);
+            }
+
+            FlushLine();
+        }
+
+        public override void EmitMethod(int offset, OpCode opCode, MethodInfo method)
+        {
+            LinePrefix(offset, opCode);
+
+            ParameterInfo[] parms = method.GetParameters();
+            int nArgs = parms.Length;
+            if(method.DeclaringType != null)
+            {
+                lbuf.Append(method.DeclaringType.Name);
+                lbuf.Append(':');
+            }
+            lbuf.Append(method.Name);
+            lbuf.Append('(');
+            for(int i = 0; i < nArgs; i++)
+            {
+                if(i > 0)
+                    lbuf.Append(",");
+                lbuf.Append(parms[i].ParameterType.Name);
+            }
+            lbuf.Append(") -> ");
+            lbuf.Append(method.ReturnType.Name);
+
+            FlushLine();
+        }
+
+        public override void EmitCtor(int offset, OpCode opCode, ConstructorInfo ctor)
+        {
+            LinePrefix(offset, opCode);
+
+            ParameterInfo[] parms = ctor.GetParameters();
+            int nArgs = parms.Length;
+            lbuf.Append(ctor.DeclaringType.Name);
+            lbuf.Append(":(");
+            for(int i = 0; i < nArgs; i++)
+            {
+                if(i > 0)
+                    lbuf.Append(",");
+                lbuf.Append(parms[i].ParameterType.Name);
+            }
+            lbuf.Append(")");
+
+            FlushLine();
+        }
+
+        public override void EmitDouble(int offset, OpCode opCode, double value)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(value.ToString());
+            lbuf.Append("   (double)");
+            FlushLine();
+        }
+
+        public override void EmitFloat(int offset, OpCode opCode, float value)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(value.ToString());
+            lbuf.Append("   (float)");
+            FlushLine();
+        }
+
+        public override void EmitInteger(int offset, OpCode opCode, int value)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append(value.ToString());
+            lbuf.Append("   (int)");
+            FlushLine();
+        }
+
+        public override void EmitString(int offset, OpCode opCode, string value)
+        {
+            LinePrefix(offset, opCode);
+            lbuf.Append("\"");
+            lbuf.Append(value);
+            lbuf.Append("\"   (string)");
+            FlushLine();
+        }
+
+        /**
+         * Put offset and opcode at beginning of line.
+         */
+        private void LinePrefix(int offset, OpCode opCode)
+        {
+            LinePrefix(offset);
+            lbuf.Append("  ");
+            lbuf.Append(opCode.ToString().PadRight(OPCSTRWIDTH - 1));
+            lbuf.Append(' ');
+        }
+
+        private void LinePrefix(int offset)
+        {
+            lbuf.Append("  ");
+            lbuf.Append(offset.ToString("X4"));
+            lbuf.Append("  ");
+        }
+
+        /**
+         * Flush line buffer to output file.
+         */
+        private void FlushLine()
+        {
+            if(lbuf.Length > 0)
+            {
+                twout.WriteLine(lbuf.ToString());
+                lbuf.Remove(0, lbuf.Length);
+            }
+        }
+    }
+
+    /****************\
+     *  DECOMPILER  *
+    \****************/
+
+    /**
+     * Note:  The decompiler does not handle any xmroption extensions
+     *        such as &&&, |||, ? operators and switch statements, as
+     *        they do branches with a non-empty stack, which is way
+     *        beyond this code's ability to analyze.
+     */
+
+    public class OTDecompile: ObjectTokens
+    {
+        public const string _mainCallNo = "__mainCallNo$";
+        public const string _callLabel = "__call_";
+        public const string _callMode = "callMode";
+        public const string _checkRunQuick = "CheckRunQuick";
+        public const string _checkRunStack = "CheckRunStack";
+        public const string _cmRestore = "__cmRestore";
+        public const string _doBreak = "dobreak_";
+        public const string _doCont = "docont_";
+        public const string _doGblInit = "doGblInit";
+        public const string _doLoop = "doloop_";
+        public const string _ehArgs = "ehArgs";
+        public const string _forBreak = "forbreak_";
+        public const string _forCont = "forcont_";
+        public const string _forLoop = "forloop_";
+        public const string _globalvarinit = "$globalvarinit()";
+        public const string _heapTrackerPop = "Pop";
+        public const string _heapTrackerPush = "Push";
+        public const string _ifDone = "ifdone_";
+        public const string _ifElse = "ifelse_";
+        public const string _llAbstemp = "llAbstemp";
+        public const string _retlbl = "__retlbl";
+        public const string _retval = "__retval$";
+        public const string _whileBreak = "whilebreak_";
+        public const string _whileCont = "whilecont_";
+        public const string _whileLoop = "whileloop_";
+        public const string _xmrinst = "__xmrinst";
+        public const string _xmrinstlocal = "__xmrinst$";
+
+        private const string INDENT = "    ";
+        private const string LABELINDENT = "  ";
+
+        private static Dictionary<string, string> typeTranslator = InitTypeTranslator();
+        private static Dictionary<string, string> InitTypeTranslator()
+        {
+            Dictionary<string, string> d = new Dictionary<string, string>();
+            d["Boolean"] = "integer";
+            d["bool"] = "integer";
+            d["Double"] = "float";
+            d["double"] = "float";
+            d["Int32"] = "integer";
+            d["int"] = "integer";
+            d["htlist"] = "list";
+            d["htobject"] = "object";
+            d["htstring"] = "string";
+            d["lslfloat"] = "float";
+            d["lslint"] = "integer";
+            d["lsllist"] = "list";
+            d["lslrot"] = "rotation";
+            d["lslstr"] = "string";
+            d["lslvec"] = "vector";
+            d["Quaternion"] = "rotation";
+            d["String"] = "string";
+            d["Vector3"] = "vector";
+            return d;
+        }
+
+        private Dictionary<int, OTLocal> eharglist;
+        private Dictionary<int, OTLabel> labels;
+        private Dictionary<int, OTLocal> locals;
+        private Dictionary<string, string[]> methargnames;
+        private LinkedList<OTCilInstr> cilinstrs;
+        private OTStmtBlock topBlock;
+        private Stack<OTOpnd> opstack;
+        private Stack<OTStmtBegExcBlk> trystack;
+        private Stack<OTStmtBlock> blockstack;
+
+        private int dupNo;
+        private DynamicMethod method;
+        private string laststate;
+        private TextWriter twout;
+
+        public OTDecompile(ScriptObjCode scriptObjCode, TextWriter twout) : base(scriptObjCode)
+        {
+            this.twout = twout;
+            twout.Write("xmroption dollarsigns;");
+            methargnames = new Dictionary<string, string[]>();
+        }
+
+        public override void Close()
+        {
+            if(laststate != null)
+            {
+                twout.Write("\n}");
+                laststate = null;
+            }
+            twout.Write('\n');
+        }
+
+        /**
+         * About to generate object code for this method.
+         */
+        public override void BegMethod(DynamicMethod method)
+        {
+            this.method = method;
+
+            eharglist = new Dictionary<int, OTLocal>();
+            labels = new Dictionary<int, OTLabel>();
+            locals = new Dictionary<int, OTLocal>();
+            cilinstrs = new LinkedList<OTCilInstr>();
+            opstack = new Stack<OTOpnd>();
+            trystack = new Stack<OTStmtBegExcBlk>();
+            blockstack = new Stack<OTStmtBlock>();
+
+            dupNo = 0;
+        }
+
+        /**
+         * Dump out reconstructed source for this method.
+         */
+        public override void EndMethod()
+        {
+            /*
+             * Convert CIL code to primitive statements.
+             * There are a bunch of labels and internal code such as call stack save restore.
+             */
+            topBlock = new OTStmtBlock();
+            blockstack.Push(topBlock);
+            for(LinkedListNode<OTCilInstr> link = cilinstrs.First; link != null; link = link.Next)
+            {
+                link.Value.BuildStatements(this, link);
+            }
+
+            /*
+             * Strip out stuff we don't want, such as references to callMode.
+             * This strips out stack frame capture and restore code.
+             */
+            topBlock.StripStuff(null);
+
+            // including a possible final return statement
+            // - delete if void return value
+            // - delete if returning __retval cuz we converted all __retval assignments to return statements
+            if((topBlock.blkstmts.Last != null) && (topBlock.blkstmts.Last.Value is OTStmtRet))
+            {
+                OTStmtRet finalret = (OTStmtRet)topBlock.blkstmts.Last.Value;
+                if((finalret.value == null) ||
+                        ((finalret.value is OTOpndLocal) &&
+                                ((OTOpndLocal)finalret.value).local.name.StartsWith(_retval)))
+                {
+                    topBlock.blkstmts.RemoveLast();
+                }
+            }
+
+            /**
+             * At this point, all behind-the-scenes references are removed except
+             * that the do/for/if/while blocks are represented by OTStmtCont-style
+             * if/jumps.  So try to convert them to the higher-level structures.
+             */
+            topBlock.DetectDoForIfWhile(null);
+
+            /*
+             * Final strip to get rid of unneeded @forbreak_<suffix>; labels and the like.
+             */
+            topBlock.StripStuff(null);
+
+            /*
+             * Build reference counts so we don't output unneeded declarations,
+             * especially temps and internal variables.
+             */
+            foreach(OTLocal local in locals.Values)
+            {
+                local.nlclreads = 0;
+                local.nlclwrites = 0;
+            }
+            topBlock.CountRefs();
+            for(IEnumerator<int> localenum = locals.Keys.GetEnumerator(); localenum.MoveNext();)
+            {
+                OTLocal local = locals[localenum.Current];
+                if(((local.nlclreads | local.nlclwrites) == 0) || local.name.StartsWith(_xmrinstlocal))
+                {
+                    locals.Remove(localenum.Current);
+                    localenum = locals.Keys.GetEnumerator();
+                }
+            }
+
+            /*
+             * Strip the $n off of local vars that are not ambiguous.
+             * Make sure they don't mask globals and arguments as well.
+             */
+            Dictionary<string, int> namecounts = new Dictionary<string, int>();
+            foreach(Dictionary<int, string> varnames in scriptObjCode.globalVarNames.Values)
+            {
+                foreach(string varname in varnames.Values)
+                {
+                    int count;
+                    if(!namecounts.TryGetValue(varname, out count))
+                        count = 0;
+                    namecounts[varname] = count + 1;
+                }
+            }
+            if(methargnames.ContainsKey(method.Name))
+            {
+                foreach(string argname in methargnames[method.Name])
+                {
+                    int count;
+                    if(!namecounts.TryGetValue(argname, out count))
+                        count = 0;
+                    namecounts[argname] = count + 1;
+                }
+            }
+            foreach(OTLocal local in locals.Values)
+            {
+                int i = local.name.LastIndexOf('$');
+                string name = local.name.Substring(0, i);
+                int count;
+                if(!namecounts.TryGetValue(name, out count))
+                    count = 0;
+                namecounts[name] = count + 1;
+            }
+            foreach(OTLocal local in locals.Values)
+            {
+                int i = local.name.LastIndexOf('$');
+                string name = local.name.Substring(0, i);
+                int count = namecounts[name];
+                if(count == 1)
+                    local.name = name;
+            }
+
+            /*
+             * Print out result.
+             */
+            if(method.Name == _globalvarinit)
+            {
+                GlobalsDump();
+            }
+            else
+            {
+                MethodDump();
+            }
+        }
+
+        /**
+         * Add instructions to stream.
+         */
+        public override void DefineLabel(int number, string name)
+        {
+            labels.Add(number, new OTLabel(number, name));
+        }
+        public override void DefineLocal(int number, string name, string type, Type syType)
+        {
+            locals.Add(number, new OTLocal(number, name, type));
+        }
+        public override void DefineMethod(string methName, Type retType, Type[] argTypes, string[] argNames)
+        {
+            methargnames[methName] = argNames;
+        }
+        public override void MarkLabel(int offset, int number)
+        {
+            OTCilInstr label = labels[number];
+            label.offset = offset;
+            cilinstrs.AddLast(label);
+        }
+        public override void BegExcBlk(int offset)
+        {
+            cilinstrs.AddLast(new OTCilBegExcBlk(offset));
+        }
+        public override void BegCatBlk(int offset, Type excType)
+        {
+            cilinstrs.AddLast(new OTCilBegCatBlk(offset, excType));
+        }
+        public override void BegFinBlk(int offset)
+        {
+            cilinstrs.AddLast(new OTCilBegFinBlk(offset));
+        }
+        public override void EndExcBlk(int offset)
+        {
+            cilinstrs.AddLast(new OTCilEndExcBlk(offset));
+        }
+        public override void EmitNull(int offset, OpCode opCode)
+        {
+            cilinstrs.AddLast(new OTCilNull(offset, opCode));
+        }
+        public override void EmitField(int offset, OpCode opCode, FieldInfo field)
+        {
+            cilinstrs.AddLast(new OTCilField(offset, opCode, field));
+        }
+        public override void EmitLocal(int offset, OpCode opCode, int number)
+        {
+            cilinstrs.AddLast(new OTCilLocal(offset, opCode, locals[number]));
+        }
+        public override void EmitType(int offset, OpCode opCode, Type type)
+        {
+            cilinstrs.AddLast(new OTCilType(offset, opCode, type));
+        }
+        public override void EmitLabel(int offset, OpCode opCode, int number)
+        {
+            cilinstrs.AddLast(new OTCilLabel(offset, opCode, labels[number]));
+        }
+        public override void EmitLabels(int offset, OpCode opCode, int[] numbers)
+        {
+            OTLabel[] labelarray = new OTLabel[numbers.Length];
+            for(int i = 0; i < numbers.Length; i++)
+            {
+                labelarray[i] = labels[numbers[i]];
+            }
+            cilinstrs.AddLast(new OTCilLabels(offset, opCode, labelarray));
+        }
+        public override void EmitMethod(int offset, OpCode opCode, MethodInfo method)
+        {
+            cilinstrs.AddLast(new OTCilMethod(offset, opCode, method));
+        }
+        public override void EmitCtor(int offset, OpCode opCode, ConstructorInfo ctor)
+        {
+            cilinstrs.AddLast(new OTCilCtor(offset, opCode, ctor));
+        }
+        public override void EmitDouble(int offset, OpCode opCode, double value)
+        {
+            cilinstrs.AddLast(new OTCilDouble(offset, opCode, value));
+        }
+        public override void EmitFloat(int offset, OpCode opCode, float value)
+        {
+            cilinstrs.AddLast(new OTCilFloat(offset, opCode, value));
+        }
+        public override void EmitInteger(int offset, OpCode opCode, int value)
+        {
+            cilinstrs.AddLast(new OTCilInteger(offset, opCode, value));
+        }
+        public override void EmitString(int offset, OpCode opCode, string value)
+        {
+            cilinstrs.AddLast(new OTCilString(offset, opCode, value));
+        }
+
+        /**
+         * Add the given statement to the end of the currently open block.
+         */
+        public void AddLastStmt(OTStmt stmt)
+        {
+            blockstack.Peek().blkstmts.AddLast(stmt);
+        }
+
+        /**
+         * Generate output for $globalvarinit() function.
+         * Also outputs declarations for global variables.
+         */
+        private void GlobalsDump()
+        {
+            /*
+             * Scan $globalvarinit().  It should only have global var assignments in it.
+             * Also gather up list of variables it initializes.
+             */
+            bool badinit = false;
+            Dictionary<string, string> inittypes = new Dictionary<string, string>();
+            foreach(OTStmt stmt in topBlock.blkstmts)
+            {
+                if(!(stmt is OTStmtStore))
+                {
+                    badinit = true;
+                    break;
+                }
+                OTStmtStore store = (OTStmtStore)stmt;
+                if(!(store.varwr is OTOpndGlobal))
+                {
+                    badinit = true;
+                    break;
+                }
+                OTOpndGlobal globalop = (OTOpndGlobal)store.varwr;
+                inittypes[globalop.PrintableString] = "";
+            }
+
+            /*
+             * Scan through list of all global variables in the script.
+             * Output declarations for those what don't have any init statement for them.
+             * Save the type for those that do have init statements.
+             */
+            bool first = true;
+            foreach(string iartypename in scriptObjCode.globalVarNames.Keys)
+            {
+                Dictionary<int, string> varnames = scriptObjCode.globalVarNames[iartypename];
+                string typename = iartypename.ToLowerInvariant();
+                if(typename.StartsWith("iar"))
+                    typename = typename.Substring(3);
+                if(typename.EndsWith("s"))
+                    typename = typename.Substring(0, typename.Length - 1);
+                foreach(string varname in varnames.Values)
+                {
+                    if(!badinit && inittypes.ContainsKey(varname))
+                    {
+                        inittypes[varname] = typename;
+                    }
+                    else
+                    {
+                        if(first)
+                            twout.Write('\n');
+                        twout.Write('\n' + typename + ' ' + varname + ';');
+                        first = false;
+                    }
+                }
+            }
+
+            /*
+             * If $globalvarinit() has anything bad in it, output it as a function.
+             * Otherwise, output it as a series of global declarations with init values.
+             */
+            if(badinit)
+            {
+                MethodDump();
+            }
+            else
+            {
+                foreach(OTStmt stmt in topBlock.blkstmts)
+                {
+                    OTStmtStore store = (OTStmtStore)stmt;
+                    OTOpndGlobal globalop = (OTOpndGlobal)store.varwr;
+                    string name = globalop.PrintableString;
+                    if(first)
+                        twout.Write('\n');
+                    twout.Write('\n' + inittypes[name] + ' ');
+                    store.PrintStmt(twout, "");
+                    first = false;
+                }
+            }
+        }
+
+        /**
+         * Generate output for other functions.
+         */
+        private void MethodDump()
+        {
+            string indent;
+
+            /*
+             * Event handlers don't have an argument list as such in the original
+             * code.  Instead they have a series of assignments from ehargs[] to
+             * local variables.  So make those local variables look like they are
+             * an argument list.
+             */
+            int i = method.Name.IndexOf(' ');
+            if(i >= 0)
+            {
+
+                /*
+                 * Maybe we have to output the state name.
+                 */
+                string statename = method.Name.Substring(0, i);
+                string eventname = method.Name.Substring(++i);
+
+                if(laststate != statename)
+                {
+                    if(laststate != null)
+                        twout.Write("\n}");
+                    if(statename == "default")
+                    {
+                        twout.Write("\n\ndefault {");
+                    }
+                    else
+                    {
+                        twout.Write("\n\nstate " + statename + " {");
+                    }
+                    laststate = statename;
+                }
+                else
+                {
+                    twout.Write('\n');
+                }
+
+                /*
+                 * Output event name and argument list.
+                 * Remove from locals list so they don't print below.
+                 */
+                twout.Write('\n' + INDENT + eventname + " (");
+                MethodInfo meth = typeof(IEventHandlers).GetMethod(eventname);
+                i = 0;
+                foreach(ParameterInfo pi in meth.GetParameters())
+                {
+                    // skip the first param cuz it's the XMRInstance arg
+                    if(i > 0)
+                        twout.Write(", ");
+                    OTLocal local;
+                    if(eharglist.TryGetValue(i, out local) && locals.ContainsKey(local.number))
+                    {
+                        twout.Write(local.DumpString());
+                        locals.Remove(local.number);
+                    }
+                    else
+                    {
+                        // maybe the assignment was removed
+                        // eg, because the local was write-only (not referenced)
+                        // so substitute in placeholder that won't be referenced
+                        twout.Write(AbbrType(pi.ParameterType) + " arg$" + (i + 1));
+                    }
+                    i++;
+                }
+                twout.Write(')');
+
+                /*
+                 * Indent method body by 4 spaces.
+                 */
+                indent = INDENT;
+            }
+            else
+            {
+
+                /*
+                 * Maybe need to close out previous state.
+                 */
+                if(laststate != null)
+                {
+                    twout.Write("\n}");
+                    laststate = null;
+                }
+
+                /*
+                 * Output blank line and return type (if any).
+                 */
+                twout.Write("\n\n");
+                if(method.ReturnType != typeof(void))
+                {
+                    twout.Write(AbbrType(method.ReturnType) + ' ');
+                }
+
+                /*
+                 * Output method name and argument list.
+                 */
+                int j = method.Name.IndexOf('(');
+                if(j < 0)
+                {
+                    twout.Write(method.Name);
+                }
+                else
+                {
+                    twout.Write(method.Name.Substring(0, j) + " (");
+                    bool first = true;
+                    j = 0;
+                    foreach(ParameterInfo pi in method.GetParameters())
+                    {
+                        if(j > 0)
+                        {  // skip the XMRInstance arg$0 parameter
+                            if(!first)
+                                twout.Write(", ");
+                            twout.Write(AbbrType(pi.ParameterType) + ' ' + MethArgName(j));
+                            first = false;
+                        }
+                        j++;
+                    }
+                    twout.Write(')');
+                }
+
+                /*
+                 * Don't indent method body at all.
+                 */
+                indent = "";
+            }
+
+            /*
+             * Output local variable declarations.
+             */
+            twout.Write('\n' + indent + '{');
+            bool didOne = false;
+            foreach(OTLocal local in locals.Values)
+            {
+                twout.Write('\n' + indent + INDENT + local.DumpString() + ";  // r:" + local.nlclreads + " w:" + local.nlclwrites);
+                didOne = true;
+            }
+            if(didOne)
+                twout.Write('\n');
+
+            /*
+             * Output statements.
+             */
+            if(topBlock.blkstmts.Count == 0)
+            {
+                twout.Write(" }");
+            }
+            else
+            {
+                topBlock.PrintBodyAndEnd(twout, indent);
+            }
+        }
+
+        /**
+         * Get abbreviated type string.
+         */
+        public static string AbbrType(Type type)
+        {
+            if(type == null)
+                return "null";
+            return AbbrType(type.Name);
+        }
+        public static string AbbrType(string type)
+        {
+            if(type.StartsWith("OpenSim.Region.ScriptEngine.YEngine."))
+            {
+                type = type.Substring(38);
+                int i = type.IndexOf(',');
+                if(i > 0)
+                    type = type.Substring(0, i);
+            }
+            if(typeTranslator.ContainsKey(type))
+            {
+                type = typeTranslator[type];
+            }
+            return type;
+        }
+
+        /**
+         * Get current method's argument name.
+         */
+        public string MethArgName(int index)
+        {
+            string[] argnames;
+            if(methargnames.TryGetValue(method.Name, out argnames) && (index < argnames.Length))
+            {
+                return argnames[index];
+            }
+            return "arg$" + index;
+        }
+
+        /**
+         * Strip svperflvovs (float) cast from rotation/vector values.
+         */
+        public static OTOpnd StripFloatCast(OTOpnd op)
+        {
+            if(op is OTOpndCast)
+            {
+                OTOpndCast opcast = (OTOpndCast)op;
+                if((opcast.type == typeof(double)) && (opcast.value is OTOpndInt))
+                {
+                    return opcast.value;
+                }
+            }
+            return op;
+        }
+
+        /**
+         * Strip svperflvovs Brtrues so we don't end up with stuff like 'if (!! someint) ...'.
+         */
+        public static OTOpnd StripBrtrue(OTOpnd op)
+        {
+            if(op is OTOpndUnOp)
+            {
+                OTOpndUnOp opunop = (OTOpndUnOp)op;
+                if(opunop.opCode == MyOp.Brtrue)
+                    return opunop.value;
+            }
+            return op;
+        }
+
+        /*
+         * Local variable declaration.
+         */
+        private class OTLocal
+        {
+            public int number;
+            public string name;
+            public string type;
+
+            public int nlclreads;
+            public int nlclwrites;
+
+            public OTLocal(int number, string name, string type)
+            {
+                this.number = number;
+                this.name = name.StartsWith("tmp$") ? name : name + "$" + number;
+                this.type = type;
+            }
+
+            public string DumpString()
+            {
+                return AbbrType(type) + ' ' + name;
+            }
+        }
+
+        /***********************************************\
+         *  Tokens that are one-for-one with CIL code  *
+        \***********************************************/
+
+        /*
+         * Part of instruction stream.
+         */
+        public abstract class OTCilInstr
+        {
+            public int offset;     // cil offset
+
+            public OTCilInstr(int offset)
+            {
+                this.offset = offset;
+            }
+
+            public abstract string DumpString();
+            public abstract void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link);
+
+            protected void CheckEmptyStack(OTDecompile decompile, string opMnemonic)
+            {
+                if(decompile.opstack.Count > 0)
+                {
+                    Console.Error.WriteLine("CheckEmptyStack: " + decompile.method.Name + " 0x" + offset.ToString("X") + ": " +
+                            opMnemonic + " stack depth " + decompile.opstack.Count);
+                }
+            }
+        }
+
+        /*
+         * Label mark point.
+         */
+        private class OTLabel: OTCilInstr
+        {
+            public int number;
+            public string name;
+
+            public int lbljumps;
+
+            public OTLabel(int number, string name) : base(-1)
+            {
+                this.number = number;
+                this.name = name;
+            }
+
+            public string PrintableName
+            {
+                get
+                {
+                    if(name.StartsWith(_doBreak))
+                        return _doBreak + "$" + number;
+                    if(name.StartsWith(_doCont))
+                        return _doCont + "$" + number;
+                    if(name.StartsWith(_forBreak))
+                        return _forBreak + "$" + number;
+                    if(name.StartsWith(_forCont))
+                        return _forCont + "$" + number;
+                    if(name.StartsWith(_whileBreak))
+                        return _whileBreak + "$" + number;
+                    if(name.StartsWith(_whileCont))
+                        return _whileCont + "$" + number;
+                    return name;
+                }
+            }
+
+            public override string DumpString()
+            {
+                return name + ":";
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                OTStmtLabel.AddLast(decompile, this);
+            }
+        }
+
+        /*
+         * 'try {'
+         */
+        private class OTCilBegExcBlk: OTCilInstr
+        {
+            public LinkedList<OTCilBegCatBlk> catches = new LinkedList<OTCilBegCatBlk>();
+
+            public OTCilBegExcBlk(int offset) : base(offset)
+            {
+            }
+
+            public override string DumpString()
+            {
+                return "try {";
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                CheckEmptyStack(decompile, "try");
+
+                // link the try itself onto outer block
+                OTStmtBegExcBlk trystmt = new OTStmtBegExcBlk();
+                decompile.AddLastStmt(trystmt);
+
+                // subsequent statements go to the try block
+                trystmt.tryblock = new OTStmtBlock();
+                decompile.trystack.Push(trystmt);
+                decompile.blockstack.Push(trystmt.tryblock);
+            }
+        }
+
+        /*
+         * '} catch (...) {'
+         */
+        private class OTCilBegCatBlk: OTCilInstr
+        {
+            public Type excType;
+
+            public OTCilBegCatBlk(int offset, Type excType) : base(offset)
+            {
+                this.excType = excType;
+            }
+
+            public override string DumpString()
+            {
+                return "} catch (" + AbbrType(excType) + ") {";
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                CheckEmptyStack(decompile, "catch");
+
+                // link the catch itself onto the try statement
+                OTStmtBegExcBlk trystmt = decompile.trystack.Peek();
+                OTStmtBegCatBlk catstmt = new OTStmtBegCatBlk(excType);
+                trystmt.catches.AddLast(catstmt);
+
+                // start capturing statements into the catch block
+                catstmt.tryblock = trystmt;
+                catstmt.catchblock = new OTStmtBlock();
+                decompile.blockstack.Pop();
+                decompile.blockstack.Push(catstmt.catchblock);
+
+                // fill the stack slot with something for the exception argument
+                OTOpndDup dup = new OTOpndDup(++decompile.dupNo);
+                decompile.opstack.Push(dup);
+            }
+        }
+
+        /*
+         * '} finally {'
+         */
+        private class OTCilBegFinBlk: OTCilInstr
+        {
+            public OTCilBegFinBlk(int offset) : base(offset)
+            {
+            }
+
+            public override string DumpString()
+            {
+                return "} finally {";
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                CheckEmptyStack(decompile, "finally");
+
+                // link the finally itself to the try statement
+                OTStmtBegExcBlk trystmt = decompile.trystack.Peek();
+                OTStmtBegFinBlk finstmt = new OTStmtBegFinBlk();
+                trystmt.finblock = finstmt;
+
+                // start capturing statements into the finally block
+                finstmt.tryblock = trystmt;
+                finstmt.finblock = new OTStmtBlock();
+                decompile.blockstack.Pop();
+                decompile.blockstack.Push(finstmt.finblock);
+            }
+        }
+
+        /*
+         * '}' end of try
+         */
+        private class OTCilEndExcBlk: OTCilInstr
+        {
+            public OTCilEndExcBlk(int offset) : base(offset)
+            {
+            }
+
+            public override string DumpString()
+            {
+                return "} // end try";
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                CheckEmptyStack(decompile, "endtry");
+
+                // pop the try/catch/finally blocks from stacks
+                decompile.blockstack.Pop();
+                decompile.trystack.Pop();
+
+                // subsequent statements collect following the try
+            }
+        }
+
+        /*
+         * Actual opcodes (instructions).
+         */
+        private class OTCilNull: OTCilInstr
+        {
+            public MyOp opCode;
+
+            public OTCilNull(int offset, OpCode opCode) : base(offset)
+            {
+                this.opCode = MyOp.GetByName(opCode.Name);
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString();
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "conv.i1":
+                    case "conv.i2":
+                    case "conv.i4":
+                    case "conv.i8":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            decompile.opstack.Push(new OTOpndCast(typeof(int), value));
+                            break;
+                        }
+                    case "conv.r4":
+                    case "conv.r8":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            decompile.opstack.Push(new OTOpndCast(typeof(double), value));
+                            break;
+                        }
+                    case "dup":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            if(!(value is OTOpndDup))
+                            {
+                                OTOpndDup dup = new OTOpndDup(++decompile.dupNo);
+                                OTStmtStore.AddLast(decompile, dup, value);
+                                value = dup;
+                            }
+                            decompile.opstack.Push(value);
+                            decompile.opstack.Push(value);
+                            break;
+                        }
+                    case "endfinally":
+                        break;
+                    case "ldarg.0":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(0, false, decompile));
+                            break;
+                        }
+                    case "ldarg.1":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(1, false, decompile));
+                            break;
+                        }
+                    case "ldarg.2":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(2, false, decompile));
+                            break;
+                        }
+                    case "ldarg.3":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(3, false, decompile));
+                            break;
+                        }
+                    case "ldc.i4.0":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(0));
+                            break;
+                        }
+                    case "ldc.i4.1":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(1));
+                            break;
+                        }
+                    case "ldc.i4.2":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(2));
+                            break;
+                        }
+                    case "ldc.i4.3":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(3));
+                            break;
+                        }
+                    case "ldc.i4.4":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(4));
+                            break;
+                        }
+                    case "ldc.i4.5":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(5));
+                            break;
+                        }
+                    case "ldc.i4.6":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(6));
+                            break;
+                        }
+                    case "ldc.i4.7":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(7));
+                            break;
+                        }
+                    case "ldc.i4.8":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(8));
+                            break;
+                        }
+                    case "ldc.i4.m1":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(-1));
+                            break;
+                        }
+                    case "ldelem.i4":
+                    case "ldelem.r4":
+                    case "ldelem.r8":
+                    case "ldelem.ref":
+                        {
+                            OTOpnd index = decompile.opstack.Pop();
+                            OTOpnd array = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndArrayElem.Make(array, index, false, decompile));
+                            break;
+                        }
+                    case "ldnull":
+                        {
+                            decompile.opstack.Push(new OTOpndNull());
+                            break;
+                        }
+                    case "neg":
+                    case "not":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndUnOp.Make(opCode, value));
+                            break;
+                        }
+                    case "pop":
+                        {
+                            OTStmtVoid.AddLast(decompile, decompile.opstack.Pop());
+                            break;
+                        }
+                    case "ret":
+                        {
+                            OTOpnd value = null;
+                            if(decompile.method.ReturnType != typeof(void))
+                            {
+                                value = decompile.opstack.Pop();
+                            }
+                            CheckEmptyStack(decompile);
+                            decompile.AddLastStmt(new OTStmtRet(value));
+                            break;
+                        }
+                    case "stelem.i4":
+                    case "stelem.r8":
+                    case "stelem.ref":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            OTOpnd index = decompile.opstack.Pop();
+                            OTOpnd array = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, OTOpndArrayElem.Make(array, index, false, decompile), value);
+                            break;
+                        }
+                    case "throw":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            CheckEmptyStack(decompile);
+                            decompile.AddLastStmt(new OTStmtThrow(value, decompile));
+                            break;
+                        }
+                    case "add":
+                    case "and":
+                    case "ceq":
+                    case "cgt":
+                    case "cgt.un":
+                    case "clt":
+                    case "clt.un":
+                    case "div":
+                    case "div.un":
+                    case "mul":
+                    case "or":
+                    case "rem":
+                    case "rem.un":
+                    case "shl":
+                    case "shr":
+                    case "shr.un":
+                    case "sub":
+                    case "xor":
+                        {
+                            OTOpnd rite = decompile.opstack.Pop();
+                            OTOpnd left = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndBinOp.Make(left, opCode, rite));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+
+            protected void CheckEmptyStack(OTDecompile decompile)
+            {
+                CheckEmptyStack(decompile, opCode.ToString());
+            }
+        }
+
+        private class OTCilField: OTCilNull
+        {
+            public FieldInfo field;
+
+            public OTCilField(int offset, OpCode opCode, FieldInfo field) : base(offset, opCode)
+            {
+                this.field = field;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + field.Name;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldfld":
+                        {
+                            OTOpnd obj = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndField.Make(obj, field));
+                            break;
+                        }
+                    case "ldsfld":
+                        {
+                            decompile.opstack.Push(new OTOpndSField(field));
+                            break;
+                        }
+                    case "stfld":
+                        {
+                            OTOpnd val = decompile.opstack.Pop();
+                            OTOpnd obj = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, OTOpndField.Make(obj, field), val);
+                            break;
+                        }
+                    case "stsfld":
+                        {
+                            OTOpnd val = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, new OTOpndSField(field), val);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilLocal: OTCilNull
+        {
+            public OTLocal local;
+
+            public OTCilLocal(int offset, OpCode opCode, OTLocal local) : base(offset, opCode)
+            {
+                this.local = local;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + local.name;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldloc":
+                        {
+                            decompile.opstack.Push(new OTOpndLocal(local));
+                            break;
+                        }
+                    case "ldloca":
+                        {
+                            decompile.opstack.Push(new OTOpndLocalRef(local));
+                            break;
+                        }
+                    case "stloc":
+                        {
+                            OTOpnd val = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, new OTOpndLocal(local), val);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilType: OTCilNull
+        {
+            public Type type;
+
+            public OTCilType(int offset, OpCode opCode, Type type) : base(offset, opCode)
+            {
+                this.type = type;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + AbbrType(type);
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "box":
+                        {
+                            break;
+                        }
+                    case "castclass":
+                    case "unbox.any":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            decompile.opstack.Push(new OTOpndCast(type, value));
+                            break;
+                        }
+                    case "ldelem":
+                        {
+                            OTOpnd index = decompile.opstack.Pop();
+                            OTOpnd array = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndArrayElem.Make(array, index, false, decompile));
+                            break;
+                        }
+                    case "ldelema":
+                        {
+                            OTOpnd index = decompile.opstack.Pop();
+                            OTOpnd array = decompile.opstack.Pop();
+                            decompile.opstack.Push(OTOpndArrayElem.Make(array, index, true, decompile));
+                            break;
+                        }
+                    case "newarr":
+                        {
+                            OTOpnd index = decompile.opstack.Pop();
+                            decompile.opstack.Push(new OTOpndNewarr(type, index));
+                            break;
+                        }
+                    case "stelem":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            OTOpnd index = decompile.opstack.Pop();
+                            OTOpnd array = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, OTOpndArrayElem.Make(array, index, false, decompile), value);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilLabel: OTCilNull
+        {
+            public OTLabel label;
+
+            public OTCilLabel(int offset, OpCode opCode, OTLabel label) : base(offset, opCode)
+            {
+                this.label = label;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + label.name;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+
+                    /*
+                     * We don't handle non-empty stack at branch points.
+                     *
+                     * So handle this case specially:
+                     *
+                     *    dup
+                     *    ldc.i4.0
+                     *    bge.s  llAbstemp  << we are here
+                     *    neg
+                     *  llAbstemp:
+                     *
+                     * becomes:
+                     *
+                     *    call llAbs
+                     */
+                    case "bge.s":
+                        {
+                            OTOpnd rite = decompile.opstack.Pop();  // alleged zero
+                            OTOpnd left = decompile.opstack.Pop();  // alleged dup
+
+                            if((label.name == _llAbstemp) && (decompile.opstack.Count > 0))
+                            {
+                                LinkedListNode<OTCilInstr> linkneg = link.Next;
+                                if((left is OTOpndDup) && (rite is OTOpndInt) &&
+                                        (linkneg != null) && (linkneg.Value is OTCilNull) &&
+                                        (((OTCilNull)linkneg.Value).opCode == MyOp.Neg))
+                                {
+                                    OTOpndInt riteint = (OTOpndInt)rite;
+                                    LinkedListNode<OTCilInstr> linklbl = linkneg.Next;
+                                    if((riteint.value == 0) && (linklbl != null) && (linklbl.Value is OTLabel) &&
+                                            (((OTLabel)linklbl.Value) == label))
+                                    {
+                                        linkneg.List.Remove(linkneg);
+                                        linklbl.List.Remove(linklbl);
+                                        MethodInfo method = typeof(ScriptBaseClass).GetMethod("llAbs");
+                                        OTOpnd[] args = new OTOpnd[] { new OTOpndNull(), decompile.opstack.Pop() };
+                                        OTOpndCall.AddLast(decompile, method, args);
+                                        break;
+                                    }
+                                }
+                            }
+
+                            CheckEmptyStack(decompile);
+                            OTOpnd valu = OTOpndBinOp.Make(left, opCode, rite);
+                            OTStmt jump = OTStmtJump.Make(label);
+                            decompile.AddLastStmt(new OTStmtCond(valu, jump));
+                            break;
+                        }
+
+                    case "beq":
+                    case "bge":
+                    case "bgt":
+                    case "ble":
+                    case "blt":
+                    case "bne.un":
+                    case "beq.s":
+                    case "bgt.s":
+                    case "ble.s":
+                    case "blt.s":
+                    case "bne.un.s":
+                        {
+                            OTOpnd rite = decompile.opstack.Pop();
+                            OTOpnd left = decompile.opstack.Pop();
+                            CheckEmptyStack(decompile);
+                            OTOpnd valu = OTOpndBinOp.Make(left, opCode, rite);
+                            OTStmt jump = OTStmtJump.Make(label);
+                            decompile.AddLastStmt(new OTStmtCond(valu, jump));
+                            break;
+                        }
+                    case "brfalse":
+                    case "brfalse.s":
+                    case "brtrue":
+                    case "brtrue.s":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            CheckEmptyStack(decompile);
+                            OTOpnd valu = OTOpndUnOp.Make(opCode, value);
+                            OTStmt jump = OTStmtJump.Make(label);
+                            decompile.AddLastStmt(new OTStmtCond(valu, jump));
+                            break;
+                        }
+                    case "br":
+                    case "br.s":
+                    case "leave":
+                        {
+                            CheckEmptyStack(decompile);
+                            OTStmt jump = OTStmtJump.Make(label);
+                            decompile.AddLastStmt(jump);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilLabels: OTCilNull
+        {
+            public OTLabel[] labels;
+
+            public OTCilLabels(int offset, OpCode opCode, OTLabel[] labels) : base(offset, opCode)
+            {
+                this.labels = labels;
+            }
+
+            public override string DumpString()
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.Append(opCode.ToString());
+                foreach(OTLabel label in labels)
+                {
+                    sb.Append(' ');
+                    sb.Append(label.name);
+                }
+                return sb.ToString();
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "switch":
+                        {
+                            OTOpnd value = decompile.opstack.Pop();
+                            CheckEmptyStack(decompile);
+                            decompile.AddLastStmt(new OTStmtSwitch(value, labels));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilMethod: OTCilNull
+        {
+            public MethodInfo method;
+
+            public OTCilMethod(int offset, OpCode opCode, MethodInfo method) : base(offset, opCode)
+            {
+                this.method = method;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + method.Name;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "call":
+                    case "callvirt":
+                        {
+                            int nargs = method.GetParameters().Length;
+                            if(!method.IsStatic)
+                                nargs++;
+                            OTOpnd[] args = new OTOpnd[nargs];
+                            for(int i = nargs; --i >= 0;)
+                            {
+                                args[i] = decompile.opstack.Pop();
+                            }
+                            OTOpndCall.AddLast(decompile, method, args);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilCtor: OTCilNull
+        {
+            public ConstructorInfo ctor;
+
+            public OTCilCtor(int offset, OpCode opCode, ConstructorInfo ctor) : base(offset, opCode)
+            {
+                this.ctor = ctor;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + AbbrType(ctor.DeclaringType);
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "newobj":
+                        {
+                            int nargs = ctor.GetParameters().Length;
+                            OTOpnd[] args = new OTOpnd[nargs];
+                            for(int i = nargs; --i >= 0;)
+                            {
+                                args[i] = decompile.opstack.Pop();
+                            }
+                            decompile.opstack.Push(OTOpndNewobj.Make(ctor, args));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilDouble: OTCilNull
+        {
+            public double value;
+
+            public OTCilDouble(int offset, OpCode opCode, double value) : base(offset, opCode)
+            {
+                this.value = value;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + value;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldc.r8":
+                        {
+                            decompile.opstack.Push(new OTOpndDouble(value));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilFloat: OTCilNull
+        {
+            public float value;
+
+            public OTCilFloat(int offset, OpCode opCode, float value) : base(offset, opCode)
+            {
+                this.value = value;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + value;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldc.r4":
+                        {
+                            decompile.opstack.Push(new OTOpndFloat(value));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilInteger: OTCilNull
+        {
+            public int value;
+
+            public OTCilInteger(int offset, OpCode opCode, int value) : base(offset, opCode)
+            {
+                this.value = value;
+            }
+
+            public override string DumpString()
+            {
+                return opCode.ToString() + ' ' + value;
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldarg":
+                    case "ldarg.s":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(value, false, decompile));
+                            break;
+                        }
+                    case "ldarga":
+                    case "ldarga.s":
+                        {
+                            decompile.opstack.Push(new OTOpndArg(value, true, decompile));
+                            break;
+                        }
+                    case "ldc.i4":
+                    case "ldc.i4.s":
+                        {
+                            decompile.opstack.Push(new OTOpndInt(value));
+                            break;
+                        }
+                    case "starg":
+                        {
+                            OTOpnd val = decompile.opstack.Pop();
+                            OTStmtStore.AddLast(decompile, new OTOpndArg(value, false, decompile), val);
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        private class OTCilString: OTCilNull
+        {
+            public string value;
+
+            public OTCilString(int offset, OpCode opCode, string value) : base(offset, opCode)
+            {
+                this.value = value;
+            }
+
+            public override string DumpString()
+            {
+                StringBuilder sb = new StringBuilder();
+                sb.Append(opCode.ToString());
+                sb.Append(' ');
+                TokenDeclInline.PrintParamString(sb, value);
+                return sb.ToString();
+            }
+
+            public override void BuildStatements(OTDecompile decompile, LinkedListNode<OTCilInstr> link)
+            {
+                switch(opCode.ToString())
+                {
+                    case "ldstr":
+                        {
+                            decompile.opstack.Push(new OTOpndString(value));
+                            break;
+                        }
+                    default:
+                        throw new Exception("unknown opcode " + opCode.ToString());
+                }
+            }
+        }
+
+        /***************************************\
+         *  Tokens what are on operand stack.  *
+        \***************************************/
+
+        public abstract class OTOpnd
+        {
+
+            /**
+             * See if it possibly has any side effects.
+             */
+            public abstract bool HasSideEffects
+            {
+                get;
+            }
+
+            /**
+             * Increment reference counts.
+             */
+            public virtual void CountRefs(bool writing)
+            {
+            }
+
+            /**
+             * If this operand is a 'by reference' operand,
+             * return the corresponding 'by value' operand.
+             */
+            public virtual OTOpnd GetNonByRefOpnd()
+            {
+                return this;
+            }
+
+            /**
+             * If this operand is same as oldopnd, replace it with newopnd.
+             *
+             * This default just does a shallow search which is ok if this operand does not have any sub-operands.
+             * But it must be overridden for a deep search if this operand has any sub-operands.
+             */
+            public virtual OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                return this;
+            }
+
+            /**
+             * See if the two operands are the same value.
+             * Note that calls might have side-effects so are never the same.
+             */
+            public abstract bool SameAs(OTOpnd other);
+
+            /**
+             * Get a printable string representation of the operand.
+             */
+            public abstract string PrintableString
+            {
+                get;
+            }
+        }
+
+        /**
+         * Argument variable.
+         */
+        private class OTOpndArg: OTOpnd
+        {
+            public int index;
+            public bool byref;
+
+            private OTDecompile decompile;
+
+            public OTOpndArg(int index, bool byref, OTDecompile decompile)
+            {
+                this.index = index;
+                this.byref = byref;
+                this.decompile = decompile;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override OTOpnd GetNonByRefOpnd()
+            {
+                if(!byref)
+                    return this;
+                return new OTOpndArg(index, false, decompile);
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndArg))
+                    return false;
+                return (((OTOpndArg)other).byref == byref) && (((OTOpndArg)other).index == index);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    string argname = decompile.MethArgName(index);
+                    return byref ? ("ref " + argname) : argname;
+                }
+            }
+        }
+
+        /**
+         * Element of an array.
+         */
+        private class OTOpndArrayElem: OTOpnd
+        {
+            public bool byref;
+            public OTOpnd array;
+            public OTOpnd index;
+
+            public static OTOpnd Make(OTOpnd array, OTOpnd index, bool byref, OTDecompile decompile)
+            {
+                /*
+                 * arg$0.glblVars.iar<type>[<intconst>] is a reference to a global variable
+                 * likewise so is __xmrinst.glblVars.iar<type>[<intconst>]
+                 */
+                if((array is OTOpndField) && (index is OTOpndInt))
+                {
+
+                    /*
+                     * arrayfield = (arg$0.glblVars).iar<type>
+                     * arrayfieldobj = arg$0.glblVars
+                     * iartypename = iar<type>
+                     */
+                    OTOpndField arrayfield = (OTOpndField)array;
+                    OTOpnd arrayfieldobj = arrayfield.obj;
+                    string iartypename = arrayfield.field.Name;
+
+                    /*
+                     * See if they are what they are supposed to be.
+                     */
+                    if((arrayfieldobj is OTOpndField) && iartypename.StartsWith("iar"))
+                    {
+
+                        /*
+                         * arrayfieldobjfield = arg$0.glblVars
+                         */
+                        OTOpndField arrayfieldobjfield = (OTOpndField)arrayfieldobj;
+
+                        /*
+                         * See if the parts are what they are supposed to be.
+                         */
+                        if(IsArg0OrXMRInst(arrayfieldobjfield.obj) && (arrayfieldobjfield.field.Name == "glblVars"))
+                        {
+
+                            /*
+                             * Everything matches up, make a global variable instead of an array reference.
+                             */
+                            return new OTOpndGlobal(iartypename, ((OTOpndInt)index).value, byref, decompile.scriptObjCode);
+                        }
+                    }
+                }
+
+                /*
+                 * Other array reference.
+                 */
+                OTOpndArrayElem it = new OTOpndArrayElem();
+                it.array = array;
+                it.index = index;
+                it.byref = byref;
+                return it;
+            }
+
+            private OTOpndArrayElem()
+            {
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return array.HasSideEffects || index.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                array.CountRefs(false);
+                index.CountRefs(false);
+            }
+
+            public override OTOpnd GetNonByRefOpnd()
+            {
+                if(!byref)
+                    return this;
+                OTOpndArrayElem it = new OTOpndArrayElem();
+                it.array = array;
+                it.index = index;
+                return it;
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                array = array.ReplaceOperand(oldopnd, newopnd, ref rc);
+                index = index.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndArrayElem))
+                    return false;
+                OTOpndArrayElem otherae = (OTOpndArrayElem)other;
+                return array.SameAs(otherae.array) && index.SameAs(otherae.index);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return (byref ? "ref " : "") + array.PrintableString + "[" + index.PrintableString + "]";
+                }
+            }
+
+            /**
+             * See if the argument is a reference to arg$0 or __xmrinst
+             */
+            public static bool IsArg0OrXMRInst(OTOpnd obj)
+            {
+                if(obj is OTOpndArg)
+                {
+                    OTOpndArg objarg = (OTOpndArg)obj;
+                    return objarg.index == 0;
+                }
+                if(obj is OTOpndLocal)
+                {
+                    OTOpndLocal objlcl = (OTOpndLocal)obj;
+                    return objlcl.local.name.StartsWith(_xmrinstlocal);
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Binary operator.
+         */
+        private class OTOpndBinOp: OTOpnd
+        {
+            public OTOpnd left;
+            public MyOp opCode;
+            public OTOpnd rite;
+
+            private static Dictionary<string, string> xor1ops = InitXor1Ops();
+
+            private static Dictionary<string, string> InitXor1Ops()
+            {
+                Dictionary<string, string> d = new Dictionary<string, string>();
+                d["ceq"] = "cne";
+                d["cge"] = "clt";
+                d["cgt"] = "cle";
+                d["cle"] = "cgt";
+                d["clt"] = "cge";
+                d["cne"] = "ceq";
+                return d;
+            }
+
+            public static OTOpnd Make(OTOpnd left, MyOp opCode, OTOpnd rite)
+            {
+                // ((x clt y) xor 1)  =>  (x cge y)  etc
+                string xor1op;
+                if((left is OTOpndBinOp) && xor1ops.TryGetValue(((OTOpndBinOp)left).opCode.name, out xor1op) &&
+                    (opCode == MyOp.Xor) &&
+                    (rite is OTOpndInt) && (((OTOpndInt)rite).value == 1))
+                {
+                    opCode = MyOp.GetByName(xor1op);
+                }
+
+                // handle strcmp() cases (see OTOpndStrCmp)
+                if(left is OTOpndStrCmp)
+                {
+                    OTOpnd strcmp = ((OTOpndStrCmp)left).MakeBinOp(opCode, rite);
+                    if(strcmp != null)
+                        return strcmp;
+                }
+
+                // nothing special, make as is
+                OTOpndBinOp it = new OTOpndBinOp();
+                it.left = left;
+                it.opCode = opCode;
+                it.rite = rite;
+                return it;
+            }
+
+            private OTOpndBinOp()
+            {
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return left.HasSideEffects || rite.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                left.CountRefs(false);
+                rite.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                left = left.ReplaceOperand(oldopnd, newopnd, ref rc);
+                rite = rite.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndBinOp))
+                    return false;
+                OTOpndBinOp otherbo = (OTOpndBinOp)other;
+                return left.SameAs(otherbo.left) && (opCode.ToString() == otherbo.opCode.ToString()) && rite.SameAs(otherbo.rite);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+
+                    bool leftneedsparen = ItNeedsParentheses(left, true);
+                    if(leftneedsparen)
+                        sb.Append('(');
+                    sb.Append(left.PrintableString);
+                    if(leftneedsparen)
+                        sb.Append(')');
+
+                    sb.Append(' ');
+                    sb.Append(opCode.source);
+                    sb.Append(' ');
+
+                    bool riteneedsparen = ItNeedsParentheses(rite, false);
+                    if(riteneedsparen)
+                        sb.Append('(');
+                    sb.Append(rite.PrintableString);
+                    if(riteneedsparen)
+                        sb.Append(')');
+
+                    return sb.ToString();
+                }
+            }
+
+            /**
+             * See if source code representation requires parentheses around the given operand.
+             * @param it = the other operand to decide about
+             * @param itleft = true: 'it' is on the left of this operand   (A $ B) # C
+             *                false: 'it' is on the right of this operand  A $ (B # C)
+             */
+            private bool ItNeedsParentheses(OTOpnd it, bool itleft)
+            {
+                if(!(it is OTOpndBinOp))
+                    return false;
+                string itop = ((OTOpndBinOp)it).opCode.source;
+                string myop = opCode.source;
+
+                // find them in table.  higher number is for *, lower is for +.
+                int itpi, mypi;
+                if(!precedence.TryGetValue(itop, out itpi))
+                    return true;
+                if(!precedence.TryGetValue(myop, out mypi))
+                    return true;
+                int itpiabs = Math.Abs(itpi);
+                int mypiabs = Math.Abs(mypi);
+
+                // if its precedence is lower (eg +) than my precedence (eg *), it needs parentheses
+                if(itpiabs < mypiabs)
+                    return true;
+
+                // if its precedence is higher (eg *) than my precedence (eg +), it doesn't needs parentheses
+                if(itpiabs > mypiabs)
+                    return false;
+
+                // if (A $ B) # C, we can safely go without the parentheses
+                if(itleft)
+                    return false;
+
+                //  my   it
+                // A $ (B # C) only works without parentheses for commutative $
+                // A - (B + C) and A - (B - C) require parentheses
+                // A + (B - C) does not
+                return mypi < 0;  // neg: things like -, /, etc require parentheses
+                                  // pos: things like +, *, etc do not need parens
+            }
+
+            // see MMRScriptReduce.PrecedenceInit()
+            private static Dictionary<string, int> precedence = InitPrecedence();
+            private static Dictionary<string, int> InitPrecedence()
+            {
+                Dictionary<string, int> d = new Dictionary<string, int>();
+                d["|"] = 140;
+                d["^"] = 160;
+                d["&"] = 180;
+                d["<<"] = -260;
+                d[">>"] = -260;
+                d["+"] = 280;
+                d["-"] = -280;
+                d["*"] = 320;
+                d["/"] = -320;
+                d["%"] = -320;
+                return d;
+            }
+        }
+
+        /**
+         * Call with or without return value.
+         */
+        private class OTOpndCall: OTOpnd
+        {
+            private static Dictionary<string, MethodInfo> mathmeths = InitMathMeths();
+            private static Dictionary<string, MethodInfo> InitMathMeths()
+            {
+                Dictionary<string, MethodInfo> d = new Dictionary<string, MethodInfo>();
+                d["Acos"] = typeof(ScriptBaseClass).GetMethod("llAcos");
+                d["Asin"] = typeof(ScriptBaseClass).GetMethod("llAsin");
+                d["Atan"] = typeof(ScriptBaseClass).GetMethod("llAtan");
+                d["Cos"] = typeof(ScriptBaseClass).GetMethod("llCos");
+                d["Abs"] = typeof(ScriptBaseClass).GetMethod("llFabs");
+                d["Log"] = typeof(ScriptBaseClass).GetMethod("llLog");
+                d["Log10"] = typeof(ScriptBaseClass).GetMethod("llLog10");
+                d["Round"] = typeof(ScriptBaseClass).GetMethod("llRound");
+                d["Sin"] = typeof(ScriptBaseClass).GetMethod("llSin");
+                d["Sqrt"] = typeof(ScriptBaseClass).GetMethod("llSqrt");
+                d["Tan"] = typeof(ScriptBaseClass).GetMethod("llTan");
+                return d;
+            }
+
+            public MethodInfo method;
+            public OTOpnd[] args;
+
+            // pushes on stack for return-value functions
+            // pushes to end of instruction stream for return-void functions
+            public static void AddLast(OTDecompile decompile, MethodInfo method, OTOpnd[] args)
+            {
+                int nargs = args.Length;
+
+                // heap tracker push is just the single arg value as far as we're concerned
+                if((nargs == 1) && (method.Name == _heapTrackerPush) && method.DeclaringType.Name.StartsWith("HeapTracker"))
+                {
+                    decompile.opstack.Push(args[0]);
+                    return;
+                }
+
+                // heap tracker pop is just a store as far as we're concerned
+                if((nargs == 2) && (method.Name == _heapTrackerPop) && method.DeclaringType.Name.StartsWith("HeapTracker"))
+                {
+                    OTStmtStore.AddLast(decompile, args[0], args[1]);
+                    return;
+                }
+
+                // string.Compare() is its own thing cuz it has to decompile many ways
+                if((nargs == 2) && (method.DeclaringType == typeof(string)) && (method.Name == "Compare"))
+                {
+                    decompile.opstack.Push(new OTOpndStrCmp(args[0], args[1]));
+                    return;
+                }
+
+                // ObjectToString, etc, should appear as casts
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToBool"))
+                {
+                    MethodInfo meth = typeof(XMRInstAbstract).GetMethod("xmr" + method.Name);
+                    AddLast(decompile, meth, new OTOpnd[] { new OTOpndNull(), args[0] });
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToFloat"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(double), args[0]));
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToInteger"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(int), args[0]));
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToList"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(LSL_List), args[0]));
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToRotation"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(LSL_Rotation), args[0]));
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToString"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(string), args[0]));
+                    return;
+                }
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.EndsWith("ToVector"))
+                {
+                    decompile.opstack.Push(new OTOpndCast(typeof(LSL_Vector), args[0]));
+                    return;
+                }
+
+                if((method.DeclaringType == typeof(XMRInstAbstract)) && (method.Name == "xmrHeapLeft"))
+                {
+                    AddLast(decompile, typeof(ScriptBaseClass).GetMethod("llGetFreeMemory"), new OTOpnd[] { new OTOpndNull() });
+                    return;
+                }
+
+                // pop to entry in the list/object/string array
+                if(PopToGlobalArray(decompile, method, args))
+                    return;
+
+                // strip off event handler argument unwrapper calls
+                if((nargs == 1) && (method.DeclaringType == typeof(TypeCast)) && method.Name.StartsWith("EHArgUnwrap"))
+                {
+                    decompile.opstack.Push(args[0]);
+                    return;
+                }
+
+                // translate Math method to ll method
+                MethodInfo mathmeth;
+                if((method.DeclaringType == typeof(Math)) && mathmeths.TryGetValue(method.Name, out mathmeth))
+                {
+                    AddLast(decompile, mathmeth, new OTOpnd[] { new OTOpndNull(), args[0] });
+                    return;
+                }
+                if((method.DeclaringType == typeof(Math)) && (method.Name == "Atan2"))
+                {
+                    AddLast(decompile, typeof(ScriptBaseClass).GetMethod("llAtan2"), new OTOpnd[] { new OTOpndNull(), args[0], args[1] });
+                    return;
+                }
+                if((method.DeclaringType == typeof(Math)) && (method.Name == "Pow"))
+                {
+                    AddLast(decompile, typeof(ScriptBaseClass).GetMethod("llPow"), new OTOpnd[] { new OTOpndNull(), args[0], args[1] });
+                    return;
+                }
+
+                // string concat should be a bunch of adds
+                if((method.Name == "Concat") && (method.DeclaringType == typeof(string)))
+                {
+                    int k = args.Length;
+                    while(k > 1)
+                    {
+                        int j = 0;
+                        int i;
+                        for(i = 0; i + 2 <= k; i += 2)
+                        {
+                            args[j++] = OTOpndBinOp.Make(args[i + 0], MyOp.Add, args[i + 1]);
+                        }
+                        while(i < k)
+                            args[j++] = args[i++];
+                        k = j;
+                    }
+                    if(k > 0)
+                        decompile.opstack.Push(args[0]);
+                    return;
+                }
+
+                // bunch of calls for rotation and vector arithmetic
+                if((method.DeclaringType == typeof(BinOpStr)) && BinOpStrCall(decompile, method, args))
+                    return;
+                if((method.DeclaringType == typeof(ScriptCodeGen)) && (method.Name == "LSLRotationNegate"))
+                {
+                    decompile.opstack.Push(OTOpndUnOp.Make(MyOp.Neg, args[0]));
+                    return;
+                }
+                if((method.DeclaringType == typeof(ScriptCodeGen)) && (method.Name == "LSLVectorNegate"))
+                {
+                    decompile.opstack.Push(OTOpndUnOp.Make(MyOp.Neg, args[0]));
+                    return;
+                }
+
+                // otherwise process it as a call
+                OTOpndCall call = new OTOpndCall();
+                call.method = method;
+                call.args = args;
+                if(method.ReturnType == typeof(void))
+                {
+                    OTStmtVoid.AddLast(decompile, call);
+                }
+                else
+                {
+                    decompile.opstack.Push(call);
+                }
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return true;
+                }
+            }
+
+            /**
+             * Handle a call to XMRInstArrays.Pop<List,Object,String>
+             * by converting it to a store directly into the array.
+             */
+            private static bool PopToGlobalArray(OTDecompile decompile, MethodInfo method, OTOpnd[] args)
+            {
+                if(method.DeclaringType != typeof(XMRInstArrays))
+                    return false;
+                if(args.Length != 3)
+                    return false;
+
+                string array = null;
+                if(method.Name == "PopList")
+                    array = "iarLists";
+                if(method.Name == "PopObject")
+                    array = "iarObjects";
+                if(method.Name == "PopString")
+                    array = "iarStrings";
+                if(array == null)
+                    return false;
+
+                // make token that points to the iar<whatever> array
+                FieldInfo field = typeof(XMRInstArrays).GetField(array);
+                OTOpnd arrayfield = OTOpndField.Make(args[0], field);
+
+                // make token that points to the element to be popped to
+                OTOpnd element = OTOpndArrayElem.Make(arrayfield, args[1], false, decompile);
+
+                // make a statement to store value in that element
+                OTStmtStore.AddLast(decompile, element, args[2]);
+
+                return true;
+            }
+
+            /**
+             * BinOpStr has a bunch of calls to do funky arithmetic.
+             * Instead of generating a call, put back the original source.
+             */
+            private static bool BinOpStrCall(OTDecompile decompile, MethodInfo method, OTOpnd[] args)
+            {
+                switch(method.Name)
+                {
+                    case "MethFloatAddList":
+                    case "MethIntAddList":
+                    case "MethKeyAddList":
+                    case "MethListAddFloat":
+                    case "MethListAddInt":
+                    case "MethListAddKey":
+                    case "MethListAddList":
+                    case "MethListAddObj":
+                    case "MethListAddRot":
+                    case "MethListAddStr":
+                    case "MethListAddVec":
+                    case "MethObjAddList":
+                    case "MethRotAddList":
+                    case "MethRotAddRot":
+                    case "MethStrAddList":
+                    case "MethVecAddList":
+                    case "MethVecAddVec":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Add, args[1]));
+                            return true;
+                        }
+
+                    case "MethListEqList":
+                    case "MethRotEqRot":
+                    case "MethVecEqVec":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Ceq, args[1]));
+                            return true;
+                        }
+
+                    case "MethListNeList":
+                    case "MethRotNeRot":
+                    case "MethVecNeVec":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Cne, args[1]));
+                            return true;
+                        }
+
+                    case "MethRotSubRot":
+                    case "MethVecSubVec":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Sub, args[1]));
+                            return true;
+                        }
+
+                    case "MethFloatMulVec":
+                    case "MethIntMulVec":
+                    case "MethRotMulRot":
+                    case "MethVecMulFloat":
+                    case "MethVecMulInt":
+                    case "MethVecMulRot":
+                    case "MethVecMulVec":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Mul, args[1]));
+                            return true;
+                        }
+
+                    case "MethRotDivRot":
+                    case "MethVecDivFloat":
+                    case "MethVecDivInt":
+                    case "MethVecDivRot":
+                        {
+                            decompile.opstack.Push(OTOpndBinOp.Make(args[0], MyOp.Div, args[1]));
+                            return true;
+                        }
+
+                    default:
+                        return false;
+                }
+            }
+
+            private OTOpndCall()
+            {
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                foreach(OTOpnd arg in args)
+                {
+                    arg.CountRefs(false);
+                }
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                for(int i = 0; i < args.Length; i++)
+                {
+                    args[i] = args[i].ReplaceOperand(oldopnd, newopnd, ref rc);
+                }
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                return false;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+
+                    // GetByKey(a,i) => a[i]
+                    if((method.DeclaringType == typeof(XMR_Array)) && (method.Name == "GetByKey") && (args.Length == 2))
+                    {
+                        sb.Append(args[0].PrintableString);
+                        sb.Append('[');
+                        sb.Append(args[1].PrintableString);
+                        sb.Append(']');
+                        return sb.ToString();
+                    }
+
+                    // SetByKey(a,i,v) => a[i] = v
+                    if((method.DeclaringType == typeof(XMR_Array)) && (method.Name == "SetByKey") && (args.Length == 3))
+                    {
+                        sb.Append(args[0].PrintableString);
+                        sb.Append('[');
+                        sb.Append(args[1].PrintableString);
+                        sb.Append("] = ");
+                        sb.Append(args[2].PrintableString);
+                        return sb.ToString();
+                    }
+
+                    // CompValuListEl.GetElementFromList accesses list elements like an array.
+                    if((method.DeclaringType == typeof(CompValuListEl)) && (method.Name == "GetElementFromList"))
+                    {
+                        sb.Append(args[0].PrintableString);
+                        sb.Append('[');
+                        sb.Append(args[1].PrintableString);
+                        sb.Append(']');
+                        return sb.ToString();
+                    }
+
+                    // methods that are part of ScriptBaseClass are LSL functions such as llSay()
+                    // so we want to skip outputting "arg$0," as it is the hidden "this" argument.
+                    // and there are also XMRInstAbstract functions such as xmrEventDequeue().
+                    int starti = 0;
+                    if((method.DeclaringType == typeof(ScriptBaseClass)) && !method.IsStatic)
+                        starti = 1;
+                    if((method.DeclaringType == typeof(XMRInstAbstract)) && !method.IsStatic)
+                        starti = 1;
+
+                    // likewise, method that have null as the declaring type are script-defined
+                    // dynamic methods which have a hidden "this" argument passed as "arg$0".
+                    if(method.DeclaringType == null)
+                        starti = 1;
+
+                    // all others we want to show the type name (such as Math.Abs, String.Compare, etc)
+                    if(starti == 0)
+                    {
+                        sb.Append(AbbrType(method.DeclaringType));
+                        sb.Append('.');
+                    }
+
+                    // script-defined functions have the param types as part of their name
+                    // so strip them off here so they don't clutter things up
+                    int i = method.Name.IndexOf('(');
+                    if(i < 0)
+                        sb.Append(method.Name);
+                    else
+                        sb.Append(method.Name.Substring(0, i));
+
+                    // now add the call arguments
+                    sb.Append(" (");
+                    bool first = true;
+                    foreach(OTOpnd arg in args)
+                    {
+                        if(--starti < 0)
+                        {
+                            if(!first)
+                                sb.Append(", ");
+                            sb.Append(arg.PrintableString);
+                            first = false;
+                        }
+                    }
+                    sb.Append(')');
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Cast value to the given type.
+         */
+        private class OTOpndCast: OTOpnd
+        {
+            public Type type;
+            public OTOpnd value;
+
+            public OTOpndCast(Type type, OTOpnd value)
+            {
+                this.type = type;
+                this.value = value;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return value.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                value.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndCast))
+                    return false;
+                OTOpndCast othercast = (OTOpndCast)other;
+                return (type == othercast.type) && value.SameAs(othercast.value);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.Append('(');
+                    sb.Append(AbbrType(type));
+                    sb.Append(") ");
+                    if(value is OTOpndBinOp)
+                        sb.Append('(');
+                    sb.Append(value.PrintableString);
+                    if(value is OTOpndBinOp)
+                        sb.Append(')');
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Duplicate stack value without re-performing computation.
+         * Semantics just like local var except it doesn't have a declaration.
+         */
+        private class OTOpndDup: OTOpnd
+        {
+            public int index;
+            public int ndupreads;
+
+            public OTOpndDup(int index)
+            {
+                this.index = index;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                if(!writing)
+                    ndupreads++;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndDup))
+                    return false;
+                return ((OTOpndDup)other).index == index;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "dup$" + index;
+                }
+            }
+        }
+
+        /**
+         * Field of an object.
+         */
+        private class OTOpndField: OTOpnd
+        {
+            public OTOpnd obj;
+            public FieldInfo field;
+
+            public static OTOpnd Make(OTOpnd obj, FieldInfo field)
+            {
+                //  LSL_Float.value => the object itself
+                if((field.DeclaringType == typeof(LSL_Float)) && (field.Name == "value"))
+                {
+                    return obj;
+                }
+
+                //  LSL_Integer.value => the object itself
+                if((field.DeclaringType == typeof(LSL_Integer)) && (field.Name == "value"))
+                {
+                    return obj;
+                }
+
+                // LSL_String.m_string => the object itself
+                if((field.DeclaringType == typeof(LSL_String)) && (field.Name == "m_string"))
+                {
+                    return obj;
+                }
+
+                // some other field, output code to access it
+                // sometimes the object comes as by reference (value types), so we might need to deref it first
+                OTOpndField it = new OTOpndField();
+                it.obj = obj.GetNonByRefOpnd();
+                it.field = field;
+                return it;
+            }
+
+            private OTOpndField()
+            {
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return obj.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                // the field may be getting written to, but the object is being read
+                obj.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                obj = obj.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndField))
+                    return false;
+                OTOpndField otherfield = (OTOpndField)other;
+                return (field.Name == otherfield.field.Name) && obj.SameAs(otherfield.obj);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    if(obj is OTOpndBinOp)
+                        sb.Append('(');
+                    sb.Append(obj.PrintableString);
+                    if(obj is OTOpndBinOp)
+                        sb.Append(')');
+                    sb.Append('.');
+                    sb.Append(field.Name);
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Script-level global variable.
+         */
+        private class OTOpndGlobal: OTOpnd
+        {
+            public string iartypename;
+            public int iararrayidx;
+            public bool byref;
+            public ScriptObjCode scriptObjCode;
+
+            public OTOpndGlobal(string iartypename, int iararrayidx, bool byref, ScriptObjCode scriptObjCode)
+            {
+                this.iartypename = iartypename;
+                this.iararrayidx = iararrayidx;
+                this.byref = byref;
+                this.scriptObjCode = scriptObjCode;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override OTOpnd GetNonByRefOpnd()
+            {
+                if(!byref)
+                    return this;
+                return new OTOpndGlobal(iartypename, iararrayidx, false, scriptObjCode);
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndGlobal))
+                    return false;
+                OTOpndGlobal otherglobal = (OTOpndGlobal)other;
+                return (iartypename == otherglobal.iartypename) && (iararrayidx == otherglobal.iararrayidx);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return (byref ? "ref " : "") + scriptObjCode.globalVarNames[iartypename][iararrayidx];
+                }
+            }
+        }
+
+        /**
+         * List initialization.
+         */
+        private class OTOpndListIni: OTOpnd
+        {
+            public OTOpnd[] values;
+
+            /**
+             * Try to detect list initialization building idiom:
+             *    dup$<n> = newarr object[<m>]      << link points here
+             *    dup$<n>[0] = bla
+             *    dup$<n>[1] = bla
+             *        ...
+             *    ... newobj list (dup$<n>) ...
+             */
+            public static bool Detect(LinkedListNode<OTStmt> link)
+            {
+                if(link == null)
+                    return false;
+
+                /*
+                 * Check for 'dup$<n> = newarr object[<m>]' and get listsize from <m>.
+                 */
+                OTStmtStore store = (OTStmtStore)link.Value;
+                if(!(store.varwr is OTOpndDup))
+                    return false;
+                if(!(store.value is OTOpndNewarr))
+                    return false;
+                OTOpndDup storevar = (OTOpndDup)store.varwr;
+                OTOpndNewarr storeval = (OTOpndNewarr)store.value;
+                if(storeval.type != typeof(object))
+                    return false;
+                if(!(storeval.index is OTOpndInt))
+                    return false;
+                int listsize = ((OTOpndInt)storeval.index).value;
+
+                /*
+                 * Good chance of having list initializer, malloc an object to hold it.
+                 */
+                OTOpndListIni it = new OTOpndListIni();
+                it.values = new OTOpnd[listsize];
+
+                /*
+                 * There should be exactly listsize statements following that of the form:
+                 *    dup$<n>[<i>] = bla
+                 * If so, save the bla values in the values[] array.
+                 */
+                LinkedListNode<OTStmt> vallink = link;
+                for(int i = 0; i < listsize; i++)
+                {
+                    vallink = vallink.Next;
+                    if(vallink == null)
+                        return false;
+                    if(!(vallink.Value is OTStmtStore))
+                        return false;
+                    OTStmtStore valstore = (OTStmtStore)vallink.Value;
+                    if(!(valstore.varwr is OTOpndArrayElem))
+                        return false;
+                    OTOpndArrayElem varelem = (OTOpndArrayElem)valstore.varwr;
+                    if(varelem.array != storevar)
+                        return false;
+                    if(!(varelem.index is OTOpndInt))
+                        return false;
+                    if(((OTOpndInt)varelem.index).value != i)
+                        return false;
+                    it.values[i] = valstore.value;
+                }
+
+                /*
+                 * The next statement should have a 'newobj list (dup$<n>)' in it somewhere
+                 * that we want to replace with 'it'.
+                 */
+                ConstructorInfo protoctor = typeof(LSL_List).GetConstructor(new Type[] { typeof(object[]) });
+                OTOpnd[] protoargs = new OTOpnd[] { storevar };
+                OTOpnd proto = OTOpndNewobj.Make(protoctor, protoargs);
+
+                vallink = vallink.Next;
+                bool rc = vallink.Value.ReplaceOperand(proto, it);
+
+                /*
+                 * If successful, delete 'dup$n =' and all 'dup$n[i] =' statements.
+                 */
+                if(rc)
+                {
+                    do
+                    {
+                        LinkedListNode<OTStmt> nextlink = link.Next;
+                        link.List.Remove(link);
+                        link = nextlink;
+                    } while(link != vallink);
+                }
+
+                return rc;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    foreach(OTOpnd value in values)
+                    {
+                        if(value.HasSideEffects)
+                            return true;
+                    }
+                    return false;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                foreach(OTOpnd value in values)
+                {
+                    value.CountRefs(false);
+                }
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                for(int i = 0; i < values.Length; i++)
+                {
+                    values[i] = values[i].ReplaceOperand(oldopnd, newopnd, ref rc);
+                }
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndListIni))
+                    return false;
+                OTOpndListIni otherli = (OTOpndListIni)other;
+                if(otherli.values.Length != values.Length)
+                    return false;
+                for(int i = 0; i < values.Length; i++)
+                {
+                    if(!values[i].SameAs(otherli.values[i]))
+                        return false;
+                }
+                return true;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.Append('[');
+                    for(int i = 0; i < values.Length; i++)
+                    {
+                        if(i > 0)
+                            sb.Append(',');
+                        sb.Append(' ');
+                        sb.Append(values[i].PrintableString);
+                    }
+                    sb.Append(" ]");
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Local variable.
+         */
+        private class OTOpndLocal: OTOpnd
+        {
+            public OTLocal local;
+
+            public OTOpndLocal(OTLocal local)
+            {
+                this.local = local;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                if(writing)
+                    local.nlclwrites++;
+                else
+                    local.nlclreads++;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndLocal))
+                    return false;
+                OTOpndLocal otherlocal = (OTOpndLocal)other;
+                return local == otherlocal.local;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return local.name;
+                }
+            }
+        }
+        private class OTOpndLocalRef: OTOpnd
+        {
+            public OTLocal local;
+
+            public OTOpndLocalRef(OTLocal local)
+            {
+                this.local = local;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return true;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                local.nlclreads++;
+                local.nlclwrites++;
+            }
+
+            public override OTOpnd GetNonByRefOpnd()
+            {
+                return new OTOpndLocal(local);
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndLocal))
+                    return false;
+                OTOpndLocal otherlocal = (OTOpndLocal)other;
+                return local == otherlocal.local;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "ref " + local.name;
+                }
+            }
+        }
+
+        /**
+         * New C#-level array.
+         */
+        private class OTOpndNewarr: OTOpnd
+        {
+            public Type type;
+            public OTOpnd index;
+
+            public OTOpndNewarr(Type type, OTOpnd index)
+            {
+                this.type = type;
+                this.index = index;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return index.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                index.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                index = index.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                return false;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "newarr " + type.Name + "[" + index.PrintableString + "]";
+                }
+            }
+        }
+
+        /**
+         * New C#-level object.
+         */
+        private class OTOpndNewobj: OTOpnd
+        {
+            public ConstructorInfo ctor;
+            public OTOpnd[] args;
+
+            public static OTOpnd Make(ConstructorInfo ctor, OTOpnd[] args)
+            {
+                // newobj LSL_Float (x)  =>  x
+                if((ctor.DeclaringType == typeof(LSL_Float)) && (args.Length == 1))
+                {
+                    Type ptype = ctor.GetParameters()[0].ParameterType;
+                    if(ptype == typeof(string))
+                    {
+                        return new OTOpndCast(typeof(double), args[0]);
+                    }
+                    return args[0];
+                }
+
+                // newobj LSL_Integer (x)  =>  x
+                if((ctor.DeclaringType == typeof(LSL_Integer)) && (args.Length == 1))
+                {
+                    Type ptype = ctor.GetParameters()[0].ParameterType;
+                    if(ptype == typeof(string))
+                    {
+                        return new OTOpndCast(typeof(int), args[0]);
+                    }
+                    return args[0];
+                }
+
+                // newobj LSL_String (x)  =>  x
+                if((ctor.DeclaringType == typeof(LSL_String)) && (args.Length == 1))
+                {
+                    return args[0];
+                }
+
+                // newobj LSL_Rotation (x, y, z, w)  =>  <x, y, z, w>
+                if((ctor.DeclaringType == typeof(LSL_Rotation)) && (args.Length == 4))
+                {
+                    return new OTOpndRot(args[0], args[1], args[2], args[3]);
+                }
+
+                // newobj LSL_Vector (x, y, z)  =>  <x, y, z>
+                if((ctor.DeclaringType == typeof(LSL_Vector)) && (args.Length == 3))
+                {
+                    return new OTOpndVec(args[0], args[1], args[2]);
+                }
+
+                // newobj LSL_Rotation (string)  => (rotation) string
+                if((ctor.DeclaringType == typeof(LSL_Rotation)) && (args.Length == 1))
+                {
+                    return new OTOpndCast(typeof(LSL_Rotation), args[0]);
+                }
+
+                // newobj LSL_Vector (string)  => (rotation) string
+                if((ctor.DeclaringType == typeof(LSL_Vector)) && (args.Length == 1))
+                {
+                    return new OTOpndCast(typeof(LSL_Vector), args[0]);
+                }
+
+                // newobj LSL_List (newarr object[0])  =>  [ ]
+                if((ctor.DeclaringType == typeof(LSL_List)) && (args.Length == 1) && (args[0] is OTOpndNewarr))
+                {
+                    OTOpndNewarr arg0 = (OTOpndNewarr)args[0];
+                    if((arg0.type == typeof(object)) && (arg0.index is OTOpndInt) && (((OTOpndInt)arg0.index).value == 0))
+                    {
+                        OTOpndListIni listini = new OTOpndListIni();
+                        listini.values = new OTOpnd[0];
+                        return listini;
+                    }
+                }
+
+                // something else, output as is
+                OTOpndNewobj it = new OTOpndNewobj();
+                it.ctor = ctor;
+                it.args = args;
+                return it;
+            }
+
+            private OTOpndNewobj()
+            {
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    foreach(OTOpnd arg in args)
+                    {
+                        if(arg.HasSideEffects)
+                            return true;
+                    }
+                    return false;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                foreach(OTOpnd arg in args)
+                {
+                    arg.CountRefs(false);
+                }
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                for(int i = 0; i < args.Length; i++)
+                {
+                    args[i] = args[i].ReplaceOperand(oldopnd, newopnd, ref rc);
+                }
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndNewobj))
+                    return false;
+                OTOpndNewobj otherno = (OTOpndNewobj)other;
+                if(otherno.ctor.DeclaringType != ctor.DeclaringType)
+                    return false;
+                if(otherno.args.Length != args.Length)
+                    return false;
+                for(int i = 0; i < args.Length; i++)
+                {
+                    if(!args[i].SameAs(otherno.args[i]))
+                        return false;
+                }
+                return true;
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.Append("newobj ");
+                    sb.Append(ctor.DeclaringType.Name);
+                    sb.Append(" (");
+                    bool first = true;
+                    foreach(OTOpnd arg in args)
+                    {
+                        if(!first)
+                            sb.Append(", ");
+                        sb.Append(arg.PrintableString);
+                        first = false;
+                    }
+                    sb.Append(')');
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Rotation value.
+         */
+        private class OTOpndRot: OTOpnd
+        {
+            private OTOpnd x, y, z, w;
+
+            public OTOpndRot(OTOpnd x, OTOpnd y, OTOpnd z, OTOpnd w)
+            {
+                this.x = StripFloatCast(x);
+                this.y = StripFloatCast(y);
+                this.z = StripFloatCast(z);
+                this.w = StripFloatCast(w);
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects || w.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                x.CountRefs(false);
+                y.CountRefs(false);
+                z.CountRefs(false);
+                w.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                x = x.ReplaceOperand(oldopnd, newopnd, ref rc);
+                y = y.ReplaceOperand(oldopnd, newopnd, ref rc);
+                z = z.ReplaceOperand(oldopnd, newopnd, ref rc);
+                w = w.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndRot))
+                    return false;
+                OTOpndRot otherv = (OTOpndRot)other;
+                return otherv.x.SameAs(x) && otherv.y.SameAs(y) && otherv.z.SameAs(z) && otherv.w.SameAs(w);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ", " + w.PrintableString + ">";
+                }
+            }
+        }
+
+        /**
+         * Static field.
+         */
+        private class OTOpndSField: OTOpnd
+        {
+            private FieldInfo field;
+
+            public OTOpndSField(FieldInfo field)
+            {
+                this.field = field;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndSField))
+                    return false;
+                OTOpndSField othersfield = (OTOpndSField)other;
+                return (field.Name == othersfield.field.Name) && (field.DeclaringType == othersfield.field.DeclaringType);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    if(field.DeclaringType == typeof(ScriptBaseClass))
+                        return field.Name;
+                    return field.DeclaringType.Name + "." + field.Name;
+                }
+            }
+        }
+
+        /**
+         * Call to string.Compare().
+         * See use cases in BinOpStr:
+         *   strcmp (a, b) ceq  0
+         *   (strcmp (a, b) ceq 0) xor 1  =>  we translate to:  strcmp (a, b) cne 0
+         *   strcmp (a, b) clt  0
+         *   strcmp (a, b) clt  1  // <=
+         *   strcmp (a, b) cgt  0
+         *   strcmp (a, b) cgt -1  // >=
+         * ...but then optimized by ScriptCollector if followed by br{false,true}:
+         *   ceq + xor 1 + brtrue  => bne.un
+         *   ceq + xor 1 + brfalse => beq
+         *   ceq + brtrue  => beq
+         *   ceq + brfalse => bne.un
+         *   cgt + brtrue  => bgt
+         *   cgt + brfalse => ble
+         *   clt + brtrue  => blt
+         *   clt + brfalse => bge
+         * So we end up with these cases:
+         *   strcmp (a, b) ceq  0
+         *   strcmp (a, b) cne  0
+         *   strcmp (a, b) clt  0
+         *   strcmp (a, b) clt  1
+         *   strcmp (a, b) cgt  0
+         *   strcmp (a, b) cgt -1
+         *   strcmp (a, b) beq    0
+         *   strcmp (a, b) bne.un 0
+         *   strcmp (a, b) bgt  0
+         *   strcmp (a, b) ble  0
+         *   strcmp (a, b) bgt -1
+         *   strcmp (a, b) ble -1
+         *   strcmp (a, b) blt  0
+         *   strcmp (a, b) bge  0
+         *   strcmp (a, b) blt  1
+         *   strcmp (a, b) bge  1
+         * ... so we pretty them up in OTOpndBinOp
+         */
+        private class OTOpndStrCmp: OTOpnd
+        {
+            private static Dictionary<string, string> binops = InitBinops();
+            private static Dictionary<string, string> InitBinops()
+            {
+                Dictionary<string, string> d = new Dictionary<string, string>();
+                d["ceq 0"] = "ceq";
+                d["cne 0"] = "cne";
+                d["clt 0"] = "clt";
+                d["clt 1"] = "cle";
+                d["cgt 0"] = "cgt";
+                d["cgt -1"] = "cge";
+                d["beq 0"] = "ceq";
+                d["bne.un 0"] = "cne";
+                d["bgt 0"] = "cgt";
+                d["ble 0"] = "cle";
+                d["bgt -1"] = "cge";
+                d["ble -1"] = "clt";
+                d["blt 0"] = "clt";
+                d["bge 0"] = "cge";
+                d["blt 1"] = "cle";
+                d["bge 1"] = "cgt";
+                return d;
+            }
+
+            private OTOpnd arg0;
+            private OTOpnd arg1;
+
+            public OTOpndStrCmp(OTOpnd arg0, OTOpnd arg1)
+            {
+                this.arg0 = arg0;
+                this.arg1 = arg1;
+            }
+
+            /**
+             * Try to make something a script writer would recognize.
+             * If we can't, then we leave it as a call to xmrStringCompare().
+             *    this   = some strcmp(a,b)
+             *    opCode = hopefully some cxx or bxx from above table
+             *    rite   = hopefully some constant from above table
+             */
+            public OTOpnd MakeBinOp(MyOp opCode, OTOpnd rite)
+            {
+                if(!(rite is OTOpndInt))
+                    return null;
+                int riteint = ((OTOpndInt)rite).value;
+                string key = opCode.name + ' ' + riteint;
+                string cxxopname;
+                if(!binops.TryGetValue(key, out cxxopname))
+                    return null;
+                return OTOpndBinOp.Make(arg0, MyOp.GetByName(cxxopname), arg1);
+            }
+            public OTOpnd MakeUnOp(MyOp opCode)
+            {
+                if(opCode == MyOp.Brfalse)
+                    return OTOpndBinOp.Make(arg0, MyOp.Ceq, arg1);
+                if(opCode == MyOp.Brtrue)
+                    return OTOpndBinOp.Make(arg0, MyOp.Cne, arg1);
+                return null;
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                arg0.CountRefs(writing);
+                arg1.CountRefs(writing);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                arg0 = arg0.ReplaceOperand(oldopnd, newopnd, ref rc);
+                arg1 = arg1.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndStrCmp))
+                    return false;
+                return arg0.SameAs(((OTOpndStrCmp)other).arg0) && arg1.SameAs(((OTOpndStrCmp)other).arg1);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "xmrStringCompare (" + arg0.PrintableString + ", " + arg1.PrintableString + ")";
+                }
+            }
+        }
+
+        /**
+         * Unary operator.
+         */
+        private class OTOpndUnOp: OTOpnd
+        {
+            public MyOp opCode;
+            public OTOpnd value;
+
+            private static Dictionary<string, string> brfops = InitBrfOps();
+            private static Dictionary<string, string> InitBrfOps()
+            {
+                Dictionary<string, string> d = new Dictionary<string, string>();
+                d["beq"] = "cne";
+                d["bge"] = "clt";
+                d["bgt"] = "cle";
+                d["ble"] = "cgt";
+                d["blt"] = "cge";
+                d["bne.un"] = "ceq";
+                d["ceq"] = "cne";
+                d["cge"] = "clt";
+                d["cgt"] = "cle";
+                d["cle"] = "cgt";
+                d["clt"] = "cge";
+                d["cne"] = "ceq";
+                return d;
+            }
+
+            public static OTOpnd Make(MyOp opCode, OTOpnd value)
+            {
+                // (brfalse (brfalse (x)))  =>  (brtrue (x))
+                if((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp)value).opCode == MyOp.Brfalse))
+                {
+                    ((OTOpndUnOp)value).opCode = MyOp.Brtrue;
+                    return value;
+                }
+
+                // (brfalse (brtrue (x)))  =>  (brfalse (x))
+                if((opCode == MyOp.Brfalse) && (value is OTOpndUnOp) && (((OTOpndUnOp)value).opCode == MyOp.Brtrue))
+                {
+                    ((OTOpndUnOp)value).opCode = MyOp.Brfalse;
+                    return value;
+                }
+
+                // (brtrue (brfalse (x)))  =>  (brfalse (x))
+                if((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp)value).opCode == MyOp.Brfalse))
+                {
+                    return value;
+                }
+
+                // (brtrue (brtrue (x)))  =>  (brtrue (x))
+                if((opCode == MyOp.Brtrue) && (value is OTOpndUnOp) && (((OTOpndUnOp)value).opCode == MyOp.Brtrue))
+                {
+                    return value;
+                }
+
+                // (brfalse (x beq y))  =>  (x bne y)  etc
+                string brfop;
+                if((opCode == MyOp.Brfalse) && (value is OTOpndBinOp) && brfops.TryGetValue(((OTOpndBinOp)value).opCode.name, out brfop))
+                {
+                    ((OTOpndBinOp)value).opCode = MyOp.GetByName(brfop);
+                    return value;
+                }
+
+                // (brtrue  (x beq y))  =>  (x beq y)  etc
+                if((opCode == MyOp.Brtrue) && (value is OTOpndBinOp) && brfops.ContainsKey(((OTOpndBinOp)value).opCode.name))
+                {
+                    return value;
+                }
+
+                // strcmp() can be a special case
+                if(value is OTOpndStrCmp)
+                {
+                    OTOpnd strcmp = ((OTOpndStrCmp)value).MakeUnOp(opCode);
+                    if(strcmp != null)
+                        return strcmp;
+                }
+
+                // nothing special, save opcode and value
+                OTOpndUnOp it = new OTOpndUnOp();
+                it.opCode = opCode;
+                it.value = value;
+                return it;
+            }
+
+            private OTOpndUnOp()
+            {
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return value.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                value.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndUnOp))
+                    return false;
+                OTOpndUnOp otherop = (OTOpndUnOp)other;
+                return (opCode.ToString() == otherop.opCode.ToString()) && value.SameAs(otherop.value);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.Append(opCode.source);
+                    sb.Append(' ');
+                    if(value is OTOpndBinOp)
+                        sb.Append('(');
+                    sb.Append(value.PrintableString);
+                    if(value is OTOpndBinOp)
+                        sb.Append(')');
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /**
+         * Vector value.
+         */
+        private class OTOpndVec: OTOpnd
+        {
+            private OTOpnd x, y, z;
+
+            public OTOpndVec(OTOpnd x, OTOpnd y, OTOpnd z)
+            {
+                this.x = StripFloatCast(x);
+                this.y = StripFloatCast(y);
+                this.z = StripFloatCast(z);
+            }
+
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return x.HasSideEffects || y.HasSideEffects || z.HasSideEffects;
+                }
+            }
+
+            public override void CountRefs(bool writing)
+            {
+                x.CountRefs(false);
+                y.CountRefs(false);
+                z.CountRefs(false);
+            }
+
+            public override OTOpnd ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd, ref bool rc)
+            {
+                if(SameAs(oldopnd))
+                {
+                    rc = true;
+                    return newopnd;
+                }
+                x = x.ReplaceOperand(oldopnd, newopnd, ref rc);
+                y = y.ReplaceOperand(oldopnd, newopnd, ref rc);
+                z = z.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return this;
+            }
+
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndVec))
+                    return false;
+                OTOpndVec otherv = (OTOpndVec)other;
+                return otherv.x.SameAs(x) && otherv.y.SameAs(y) && otherv.z.SameAs(z);
+            }
+
+            public override string PrintableString
+            {
+                get
+                {
+                    return "<" + x.PrintableString + ", " + y.PrintableString + ", " + z.PrintableString + ">";
+                }
+            }
+        }
+
+        /**
+         * Constants.
+         */
+        private class OTOpndDouble: OTOpnd
+        {
+            public double value;
+            public OTOpndDouble(double value)
+            {
+                this.value = value;
+            }
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndDouble))
+                    return false;
+                return ((OTOpndDouble)other).value == value;
+            }
+            public override string PrintableString
+            {
+                get
+                {
+                    string s = value.ToString();
+                    long i;
+                    if(long.TryParse(s, out i))
+                    {
+                        s += ".0";
+                    }
+                    return s;
+                }
+            }
+        }
+        private class OTOpndFloat: OTOpnd
+        {
+            public float value;
+            public OTOpndFloat(float value)
+            {
+                this.value = value;
+            }
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndFloat))
+                    return false;
+                return ((OTOpndFloat)other).value == value;
+            }
+            public override string PrintableString
+            {
+                get
+                {
+                    string s = value.ToString();
+                    long i;
+                    if(long.TryParse(s, out i))
+                    {
+                        s += ".0";
+                    }
+                    return s;
+                }
+            }
+        }
+        private class OTOpndInt: OTOpnd
+        {
+            public int value;
+            public OTOpndInt(int value)
+            {
+                this.value = value;
+            }
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndInt))
+                    return false;
+                return ((OTOpndInt)other).value == value;
+            }
+            public override string PrintableString
+            {
+                get
+                {
+                    return value.ToString();
+                }
+            }
+        }
+        private class OTOpndNull: OTOpnd
+        {
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool SameAs(OTOpnd other)
+            {
+                return other is OTOpndNull;
+            }
+            public override string PrintableString
+            {
+                get
+                {
+                    return "undef";
+                }
+            }
+        }
+        private class OTOpndString: OTOpnd
+        {
+            public string value;
+            public OTOpndString(string value)
+            {
+                this.value = value;
+            }
+            public override bool HasSideEffects
+            {
+                get
+                {
+                    return false;
+                }
+            }
+            public override bool SameAs(OTOpnd other)
+            {
+                if(!(other is OTOpndString))
+                    return false;
+                return ((OTOpndString)other).value == value;
+            }
+            public override string PrintableString
+            {
+                get
+                {
+                    StringBuilder sb = new StringBuilder();
+                    TokenDeclInline.PrintParamString(sb, value);
+                    return sb.ToString();
+                }
+            }
+        }
+
+        /****************************************\
+         *  Tokens what are in statement list.  *
+        \****************************************/
+
+        public abstract class OTStmt
+        {
+
+            /**
+             * Increment reference counts.
+             */
+            public abstract void CountRefs();
+
+            /**
+             * Strip out any of the behind-the-scenes code such as stack capture/restore.
+             * By default, there is no change.
+             */
+            public virtual bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                return false;
+            }
+
+            /**
+             * Replace the oldopnd operand with the newopnd operand if it is present.
+             * Return whether or not it was found and replaced.
+             */
+            public abstract bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd);
+
+            /**
+             * Detect and modify for do/for/if/while structures.
+             */
+            public virtual bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return false;
+            }
+
+            /**
+             * If this statement is the old statement, replace it with the given new statement.
+             * Also search any sub-ordinate statements.
+             * **NOTE**: minimally implemented to replace a Jump with a Break or Continue
+             */
+            public abstract OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt);
+
+            /**
+             * Print the statement out on the given printer with the given indenting.
+             * The first line is already indented, subsequent lines must be indented as given.
+             * This method should leave the printer at the end of the line.
+             */
+            public abstract void PrintStmt(TextWriter twout, string indent);
+
+            /**
+             * Strip all statements following this statement
+             * because this statement jumps somewhere.
+             */
+            protected bool StripStuffForTerminal(LinkedListNode<OTStmt> link)
+            {
+                // strip all statements following jump until seeing some label
+                bool rc = false;
+                if(link != null)
+                {
+                    LinkedListNode<OTStmt> nextlink;
+                    while((nextlink = link.Next) != null)
+                    {
+                        if(nextlink.Value is OTStmtLabel)
+                            break;
+                        nextlink.List.Remove(nextlink);
+                        rc = true;
+                    }
+                }
+                return rc;
+            }
+        }
+
+        /**************************\
+         *  Primitive statements  *
+        \**************************/
+
+        /**
+         * Begin catch block (catch).
+         */
+        private class OTStmtBegCatBlk: OTStmt
+        {
+            public OTStmtBegExcBlk tryblock;
+            public OTStmtBlock catchblock;
+
+            private Type excType;
+
+            public OTStmtBegCatBlk(Type excType)
+            {
+                this.excType = excType;
+            }
+
+            public override void CountRefs()
+            {
+                catchblock.CountRefs();
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                return catchblock.StripStuff(null);
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return catchblock.ReplaceOperand(oldopnd, newopnd);
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return catchblock.DetectDoForIfWhile(link);
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                catchblock = (OTStmtBlock)catchblock.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            /**
+             * Print out the catch block including its enclosed statements.
+             */
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("catch (" + excType.Name + ") ");
+                catchblock.PrintStmt(twout, indent);
+            }
+        }
+
+        /**
+         * Begin exception block (try).
+         */
+        private class OTStmtBegExcBlk: OTStmt
+        {
+
+            // statements within the try { } not including any catch or finally
+            public OTStmtBlock tryblock;
+
+            // list of all catch { } blocks associated with this try { }
+            public LinkedList<OTStmtBegCatBlk> catches = new LinkedList<OTStmtBegCatBlk>();
+
+            // possible single finally { } associated with this try
+            public OTStmtBegFinBlk finblock;  // might be null
+
+            public override void CountRefs()
+            {
+                tryblock.CountRefs();
+                foreach(OTStmtBegCatBlk catblock in catches)
+                {
+                    catblock.CountRefs();
+                }
+                if(finblock != null)
+                    finblock.CountRefs();
+            }
+
+            /**
+             * Strip behind-the-scenes info from all the sub-blocks.
+             */
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // strip behind-the-scenes info from all the sub-blocks.
+                bool rc = tryblock.StripStuff(null);
+                foreach(OTStmtBegCatBlk catblk in catches)
+                {
+                    rc |= catblk.StripStuff(null);
+                }
+                if(finblock != null)
+                    rc |= finblock.StripStuff(null);
+                if(rc)
+                    return true;
+
+                // change:
+                //    try {
+                //       ...
+                //    }
+                // to:
+                //    {
+                //       ...
+                //    }
+                // note that an empty catch () { } has meaning so can't be stripped
+                // empty finally { } blocks strips itself from the try
+                if((catches.Count == 0) && (finblock == null) && (link != null))
+                {
+                    link.List.AddAfter(link, tryblock);
+                    tryblock = null;
+                    link.List.Remove(link);
+                    return true;
+                }
+
+                return false;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = tryblock.ReplaceOperand(oldopnd, newopnd);
+                foreach(OTStmtBegCatBlk catblk in catches)
+                {
+                    rc |= catblk.ReplaceOperand(oldopnd, newopnd);
+                }
+                if(finblock != null)
+                    rc |= finblock.ReplaceOperand(oldopnd, newopnd);
+                return rc;
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                bool rc = tryblock.DetectDoForIfWhile(link);
+                foreach(OTStmtBegCatBlk catblk in catches)
+                {
+                    rc |= catblk.DetectDoForIfWhile(link);
+                }
+                if(finblock != null)
+                    rc |= finblock.DetectDoForIfWhile(link);
+                return rc;
+            }
+
+            /**
+             * Assume we will never try to replace the try block itself.
+             * But go through all our sub-ordinates statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                tryblock = (OTStmtBlock)tryblock.ReplaceStatement(oldstmt, newstmt);
+                for(LinkedListNode<OTStmtBegCatBlk> catlink = catches.First; catlink != null; catlink = catlink.Next)
+                {
+                    catlink.Value = (OTStmtBegCatBlk)catlink.Value.ReplaceStatement(oldstmt, newstmt);
+                }
+                if(finblock != null)
+                    finblock = (OTStmtBegFinBlk)finblock.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            /**
+             * Print out the try block including its enclosed statements.
+             * And since the try is the only thing pushed to the outer block,
+             * we also print out all the catch and finally blocks.
+             */
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("try ");
+                tryblock.PrintStmt(twout, indent);
+                foreach(OTStmtBegCatBlk catblk in catches)
+                {
+                    twout.Write(' ');
+                    catblk.PrintStmt(twout, indent);
+                }
+                if(finblock != null)
+                {
+                    twout.Write(' ');
+                    finblock.PrintStmt(twout, indent);
+                }
+            }
+        }
+
+        /**
+         * Begin finally block (finally).
+         */
+        private class OTStmtBegFinBlk: OTStmt
+        {
+            public OTStmtBegExcBlk tryblock;
+            public OTStmtBlock finblock;
+
+            public override void CountRefs()
+            {
+                finblock.CountRefs();
+            }
+
+            /**
+             * Strip behind-the-scene parts from the finally block.
+             */
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // strip behind-the-scenes parts from finally block itself
+                if(finblock.StripStuff(null))
+                    return true;
+
+                // if finblock is empty, delete the finally from the try
+                if(finblock.blkstmts.Count == 0)
+                {
+                    tryblock.finblock = null;
+                    return true;
+                }
+
+                return false;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return finblock.ReplaceOperand(oldopnd, newopnd);
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return finblock.DetectDoForIfWhile(link);
+            }
+
+            /**
+             * Assume we will never try to replace the finally block itself.
+             * But go through all our sub-ordinates statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                finblock = (OTStmtBlock)finblock.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            /**
+             * Print out the finally block including its enclosed statements.
+             */
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("finally ");
+                finblock.PrintStmt(twout, indent);
+            }
+        }
+
+        /**
+         * Simple if jump/break/continue statement.
+         */
+        private class OTStmtCond: OTStmt
+        {
+            public OTOpnd valu;
+            public OTStmt stmt;  // jump, break, continue only
+
+            public OTStmtCond(OTOpnd valu, OTStmt stmt)
+            {
+                this.valu = valu;
+                this.stmt = stmt;
+            }
+
+            public override void CountRefs()
+            {
+                valu.CountRefs(false);
+                stmt.CountRefs();
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // we assume that callMode is always CallMode_NORMAL, ie, not doing a stack capture or restore
+                // so the 'if (arg$0.callMode bne.un 0) ...' is deleted
+                // and the 'if (arg$0.callMode bne.un 1) ...' becomes unconditional
+                // it can also be __xmrinst.callMode instead of arg$0
+                if(valu is OTOpndBinOp)
+                {
+                    OTOpndBinOp binop = (OTOpndBinOp)valu;
+                    if((binop.left is OTOpndField) && (binop.opCode.ToString() == "bne.un") && (binop.rite is OTOpndInt))
+                    {
+                        OTOpndField leftfield = (OTOpndField)binop.left;
+                        if(leftfield.field.Name == _callMode)
+                        {
+                            bool ok = false;
+                            if(leftfield.obj is OTOpndArg)
+                            {
+                                ok = ((OTOpndArg)leftfield.obj).index == 0;
+                            }
+                            if(leftfield.obj is OTOpndLocal)
+                            {
+                                ok = ((OTOpndLocal)leftfield.obj).local.name.StartsWith(_xmrinstlocal);
+                            }
+                            if(ok)
+                            {
+                                OTOpndInt riteint = (OTOpndInt)binop.rite;
+
+                                // delete 'if ((arg$0).callMode bne.un 0) ...'
+                                if(riteint.value == XMRInstAbstract.CallMode_NORMAL)
+                                {
+                                    link.List.Remove(link);
+                                    return true;
+                                }
+
+                                // make 'if ((arg$0).callMode bne.un 1) ...' unconditional
+                                if(riteint.value == XMRInstAbstract.CallMode_SAVE)
+                                {
+                                    link.Value = stmt;
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // similarly we assume that doGblInit is always 0 to eliminate the code at beginning of default state_entry()
+                // so the 'if (brfalse __xmrinst.doGblInit) ...' is made unconditional
+                if(valu is OTOpndUnOp)
+                {
+                    OTOpndUnOp unop = (OTOpndUnOp)valu;
+                    if((unop.opCode == MyOp.Brfalse) && (unop.value is OTOpndField))
+                    {
+                        OTOpndField valuefield = (OTOpndField)unop.value;
+                        if(valuefield.field.Name == _doGblInit)
+                        {
+                            bool ok = false;
+                            if(valuefield.obj is OTOpndLocal)
+                            {
+                                ok = ((OTOpndLocal)valuefield.obj).local.name.StartsWith(_xmrinstlocal);
+                            }
+                            if(ok)
+                            {
+
+                                // make 'if (brfalse __xmrinst.doGblInit) ...' unconditional
+                                link.Value = stmt;
+                                return true;
+                            }
+                        }
+                    }
+                }
+
+                return false;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = stmt.ReplaceOperand(oldopnd, newopnd);
+                valu = valu.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            /**
+             * Maybe this simple if statement is part of a script-level if/then/else statement.
+             */
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return OTStmtIf.Detect(link);
+            }
+
+            /**
+             * Assume we won't replace the if statement itself.
+             * But search all our sub-ordinate statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                stmt = stmt.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("if (" + StripBrtrue(valu).PrintableString + ") ");
+                stmt.PrintStmt(twout, indent);
+            }
+
+            /**
+             * Scan forward for a given label definition.
+             * Put intervening statements in a statement block.
+             * @param link = start scanning after this statement
+             * @param label = look for this label definition
+             * @param block = where to return intervening statement block
+             * @returns null: label definition not found
+             *          else: label definition statement
+             */
+            private static LinkedListNode<OTStmt> ScanForLabel(LinkedListNode<OTStmt> link,
+                        OTLabel label, out OTStmtBlock block)
+            {
+                block = new OTStmtBlock();
+                while((link = link.Next) != null)
+                {
+                    if(link.Value is OTStmtLabel)
+                    {
+                        if(((OTStmtLabel)link.Value).label == label)
+                            break;
+                    }
+                    block.blkstmts.AddLast(link.Value);
+                }
+                return link;
+            }
+
+            /**
+             * Strip statements after link up to and including donelink.
+             */
+            private static void StripInterveningStatements(LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
+            {
+                LinkedListNode<OTStmt> striplink;
+                do
+                {
+                    striplink = link.Next;
+                    striplink.List.Remove(striplink);
+                } while(striplink != donelink);
+            }
+        }
+
+        /**
+         * Jump to a label.
+         */
+        private class OTStmtJump: OTStmt
+        {
+            public OTLabel label;
+
+            public static OTStmt Make(OTLabel label)
+            {
+                // jumps to __retlbl are return statements
+                // note that is is safe to say it is a valueless return because
+                // valued returns are done with this construct:
+                //    __retval = ....;
+                //    jump __retlbl;
+                // and those __retval = statements have been changed to return statements already
+                if(label.name.StartsWith(_retlbl))
+                    return new OTStmtRet(null);
+
+                // other jumps are really jumps
+                OTStmtJump it = new OTStmtJump();
+                it.label = label;
+                return it;
+            }
+
+            private OTStmtJump()
+            {
+            }
+
+            public override void CountRefs()
+            {
+                label.lbljumps++;
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                if(link == null)
+                    return false;
+
+                // strip statements following unconditional jump until next label
+                bool rc = StripStuffForTerminal(link);
+
+                // if we (now) have:
+                //      jump label;
+                //   @label;
+                // ... delete this jump
+                if(link.Next != null)
+                {
+                    OTStmtLabel nextlabel = (OTStmtLabel)link.Next.Value;
+                    if(nextlabel.label == label)
+                    {
+                        link.List.Remove(link);
+                        rc = true;
+                    }
+                }
+
+                return rc;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return false;
+            }
+
+            /**
+             * This is actually what ReplaceStatement() is currently used for.
+             * It replaces a jump with a break or a continue.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                if((oldstmt is OTStmtJump) && (((OTStmtJump)oldstmt).label == label))
+                    return newstmt;
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("jump " + label.PrintableName + ';');
+            }
+        }
+
+        /**
+         * Label definition point.
+         */
+        private class OTStmtLabel: OTStmt
+        {
+            public OTLabel label;
+
+            private OTDecompile decompile;
+
+            public static void AddLast(OTDecompile decompile, OTLabel label)
+            {
+                OTStmtLabel it = new OTStmtLabel();
+                it.label = label;
+                it.decompile = decompile;
+                decompile.AddLastStmt(it);
+            }
+
+            private OTStmtLabel()
+            {
+            }
+
+            public override void CountRefs()
+            {
+                // don't increment label.lbljumps
+                // cuz we don't want the positioning
+                // to count as a reference, only jumps
+                // to the label should count
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // if label has nothing jumping to it, remove the label
+                if(link != null)
+                {
+                    label.lbljumps = 0;
+                    decompile.topBlock.CountRefs();
+                    if(label.lbljumps == 0)
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return false;
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                if(OTStmtDo.Detect(link))
+                    return true;
+                if(OTStmtFor.Detect(link, true))
+                    return true;
+                if(OTStmtFor.Detect(link, false))
+                    return true;
+                return false;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("@" + label.PrintableName + ';');
+            }
+        }
+
+        /**
+         * Return with or without value.
+         */
+        private class OTStmtRet: OTStmt
+        {
+            public OTOpnd value;  // might be null
+
+            public OTStmtRet(OTOpnd value)
+            {
+                this.value = value;
+            }
+
+            public override void CountRefs()
+            {
+                if(value != null)
+                    value.CountRefs(false);
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                return StripStuffForTerminal(link);
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                if(value != null)
+                    value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                if(value == null)
+                {
+                    twout.Write("return;");
+                }
+                else
+                {
+                    twout.Write("return " + value.PrintableString + ';');
+                }
+            }
+        }
+
+        /**
+         * Store value in variable.
+         */
+        private class OTStmtStore: OTStmt
+        {
+            public OTOpnd varwr;
+            public OTOpnd value;
+
+            private OTDecompile decompile;
+
+            public static void AddLast(OTDecompile decompile, OTOpnd varwr, OTOpnd value)
+            {
+                OTStmtStore it = new OTStmtStore(varwr, value, decompile);
+                decompile.AddLastStmt(it);
+            }
+
+            public OTStmtStore(OTOpnd varwr, OTOpnd value, OTDecompile decompile)
+            {
+                this.varwr = varwr;
+                this.value = value;
+                this.decompile = decompile;
+            }
+
+            public override void CountRefs()
+            {
+                varwr.CountRefs(true);
+                value.CountRefs(false);
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // strip out stores to __mainCallNo
+                if(varwr is OTOpndLocal)
+                {
+                    OTOpndLocal local = (OTOpndLocal)varwr;
+                    if(local.local.name.StartsWith(_mainCallNo))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                // strip out stores to local vars where the var is not read
+                // but convert the value to an OTStmtVoid in case it is a call
+                if(varwr is OTOpndLocal)
+                {
+                    OTOpndLocal local = (OTOpndLocal)varwr;
+                    local.local.nlclreads = 0;
+                    decompile.topBlock.CountRefs();
+                    if(local.local.nlclreads == 0)
+                    {
+                        OTStmt voidstmt = OTStmtVoid.Make(value);
+                        if(voidstmt == null)
+                            link.List.Remove(link);
+                        else
+                            link.Value = voidstmt;
+                        return true;
+                    }
+                }
+
+                // strip out bla = newobj HeapTrackerList (...);
+                if(value is OTOpndNewobj)
+                {
+                    OTOpndNewobj valueno = (OTOpndNewobj)value;
+                    if(valueno.ctor.DeclaringType == typeof(HeapTrackerList))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                // strip out bla = newobj HeapTrackerObject (...);
+                if(value is OTOpndNewobj)
+                {
+                    OTOpndNewobj valueno = (OTOpndNewobj)value;
+                    if(valueno.ctor.DeclaringType == typeof(HeapTrackerObject))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                // strip out bla = newobj HeapTrackerString (...);
+                if(value is OTOpndNewobj)
+                {
+                    OTOpndNewobj valueno = (OTOpndNewobj)value;
+                    if(valueno.ctor.DeclaringType == typeof(HeapTrackerString))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                // convert tmp$n = bla bla;
+                //         ....  tmp$n  ....;
+                // to
+                //         ....  bla bla  ....;
+                // gets rid of vast majority of temps
+                if(varwr is OTOpndLocal)
+                {
+                    OTOpndLocal temp = (OTOpndLocal)varwr;
+                    if(temp.local.name.StartsWith("tmp$"))
+                    {
+                        temp.local.nlclreads = 0;
+                        temp.local.nlclwrites = 0;
+                        decompile.topBlock.CountRefs();
+                        if((temp.local.nlclreads == 1) && (temp.local.nlclwrites == 1) && (link.Next != null))
+                        {
+                            OTStmt nextstmt = link.Next.Value;
+                            if(!(nextstmt is OTStmtBlock))
+                            {
+                                if(nextstmt.ReplaceOperand(varwr, value))
+                                {
+                                    link.List.Remove(link);
+                                    return true;
+                                }
+                            }
+                        }
+
+                        // also try to convert:
+                        //    tmp$n = ... asdf ...  << we are here (link)
+                        //    lcl = tmp$n;          << nextstore
+                        //    ... qwer tmp$n ...
+                        //    ... no further references to tmp$n
+                        // to:
+                        //    lcl = ... asdf ...
+                        //    ... qwer lcl ...
+                        if((temp.local.nlclreads == 2) && (temp.local.nlclwrites == 1) &&
+                                (link.Next != null) && (link.Next.Value is OTStmtStore))
+                        {
+                            OTStmtStore nextstore = (OTStmtStore)link.Next.Value;
+                            if((nextstore.varwr is OTOpndLocal) && (nextstore.value is OTOpndLocal) && (link.Next.Next != null))
+                            {
+                                OTOpndLocal localopnd = (OTOpndLocal)nextstore.varwr;
+                                OTOpndLocal tempopnd = (OTOpndLocal)nextstore.value;
+                                if(tempopnd.local == temp.local)
+                                {
+                                    OTStmt finalstmt = link.Next.Next.Value;
+                                    if(finalstmt.ReplaceOperand(tempopnd, localopnd))
+                                    {
+                                        nextstore.value = value;
+                                        link.List.Remove(link);
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // convert:
+                //    dup$n = ... asdf ...  << we are here
+                //    lcl = dup$n;
+                //    ... qwer dup$n ...
+                //    ... no further references to dup$n
+                // to:
+                //    lcl = ... asdf ...
+                //    ... qwer lcl ...
+                if((varwr is OTOpndDup) && (link != null))
+                {
+                    OTOpndDup vardup = (OTOpndDup)varwr;
+                    LinkedListNode<OTStmt> nextlink = link.Next;
+                    vardup.ndupreads = 0;
+                    decompile.topBlock.CountRefs();
+                    if((vardup.ndupreads == 2) && (nextlink != null) && (nextlink.Value is OTStmtStore))
+                    {
+
+                        // point to the supposed lcl = dup$n statement
+                        OTStmtStore nextstore = (OTStmtStore)nextlink.Value;
+                        LinkedListNode<OTStmt> nextlink2 = nextlink.Next;
+                        if((nextstore.varwr is OTOpndLocal) && (nextstore.value == vardup) && (nextlink2 != null))
+                        {
+
+                            // get the local var being written and point to the ... qwer dup$n ... statement
+                            OTOpndLocal varlcl = (OTOpndLocal)nextstore.varwr;
+                            OTStmt nextstmt2 = nextlink2.Value;
+
+                            // try to replace dup$n in qwer with lcl
+                            if(nextstmt2.ReplaceOperand(vardup, varlcl))
+                            {
+
+                                // successful, replace dup$n in asdf with lcl
+                                // and delete the lcl = dup$n statement
+                                varwr = varlcl;
+                                nextlink.List.Remove(nextlink);
+                                return true;
+                            }
+                        }
+                    }
+                }
+
+                // convert:
+                //    dup$n = ... asdf ...  << we are here
+                //    ... qwer dup$n ...
+                //    ... no further references to dup$n
+                // to:
+                //    ... qwer ... asdf ... ...
+                if((varwr is OTOpndDup) && (link != null))
+                {
+                    OTOpndDup vardup = (OTOpndDup)varwr;
+                    LinkedListNode<OTStmt> nextlink = link.Next;
+                    vardup.ndupreads = 0;
+                    decompile.topBlock.CountRefs();
+                    if((vardup.ndupreads == 1) && (nextlink != null))
+                    {
+
+                        // point to the ... qwer dup$n ... statement
+                        OTStmt nextstmt = nextlink.Value;
+
+                        // try to replace dup$n in qwer with ... asdf ...
+                        if(nextstmt.ReplaceOperand(vardup, value))
+                        {
+
+                            // successful, delete the dup$n = ... asdf ... statement
+                            link.List.Remove(link);
+                            return true;
+                        }
+                    }
+                }
+
+                // look for list initialization [ ... ]
+                if(OTOpndListIni.Detect(link))
+                    return true;
+
+                // __xmrinst = (XMRInstAbstract) arg$0 indicates this is an event handler
+                // so strip it out and set the flag
+                if((varwr is OTOpndLocal) && (value is OTOpndCast))
+                {
+                    OTOpndLocal lcl = (OTOpndLocal)varwr;
+                    OTOpndCast cast = (OTOpndCast)value;
+                    if(lcl.local.name.StartsWith(_xmrinstlocal) && (cast.value is OTOpndArg))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                // local = [ (optional cast) ] __xmrinst.ehArgs[n] is a definition of event handler arg #n
+                // if found, make it event handler arg list definition
+                OTOpnd valuenocast = value;
+                if(valuenocast is OTOpndCast)
+                    valuenocast = ((OTOpndCast)value).value;
+                if((varwr is OTOpndLocal) && (valuenocast is OTOpndArrayElem))
+                {
+                    OTOpndArrayElem array = (OTOpndArrayElem)valuenocast;
+                    if((array.array is OTOpndField) && (array.index is OTOpndInt))
+                    {
+                        OTOpndField arrayfield = (OTOpndField)array.array;
+                        if((arrayfield.obj is OTOpndLocal) &&
+                                ((OTOpndLocal)arrayfield.obj).local.name.StartsWith(_xmrinstlocal) &&
+                                (arrayfield.field.Name == _ehArgs))
+                        {
+                            int index = ((OTOpndInt)array.index).value;
+                            decompile.eharglist[index] = ((OTOpndLocal)varwr).local;
+                            link.List.Remove(link);
+                            return true;
+                        }
+                    }
+                }
+
+                // __retval$n = ...;  =>  return ...;
+                if(varwr is OTOpndLocal)
+                {
+                    OTOpndLocal lcl = (OTOpndLocal)varwr;
+                    if(lcl.local.name.StartsWith(_retval))
+                    {
+                        link.Value = new OTStmtRet(value);
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                if(value != null)
+                    value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                // print x = x + 1 as x += 1, but don't print x = x < 3 as x <= 3
+                if(value is OTOpndBinOp)
+                {
+                    OTOpndBinOp valuebo = (OTOpndBinOp)value;
+                    if(varwr.SameAs(valuebo.left) && " add and div mul or rem shl shr sub xor ".Contains(' ' + valuebo.opCode.name + ' '))
+                    {
+                        twout.Write(varwr.PrintableString + ' ' + valuebo.opCode.source + "= " + valuebo.rite.PrintableString + ';');
+                        return;
+                    }
+                }
+
+                twout.Write(varwr.PrintableString + " = " + value.PrintableString + ';');
+            }
+        }
+
+        /**
+         * Dispatch to a table of labels.
+         */
+        private class OTStmtSwitch: OTStmt
+        {
+            private OTOpnd index;
+            private OTLabel[] labels;
+
+            public OTStmtSwitch(OTOpnd index, OTLabel[] labels)
+            {
+                this.index = index;
+                this.labels = labels;
+            }
+
+            public override void CountRefs()
+            {
+                index.CountRefs(false);
+                foreach(OTLabel label in labels)
+                {
+                    label.lbljumps++;
+                }
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                if(index != null)
+                    index = index.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("switch (" + index.PrintableString + ") {\n");
+                for(int i = 0; i < labels.Length; i++)
+                {
+                    twout.Write(indent + INDENT + "case " + i + ": jump " + labels[i].name + ";\n");
+                }
+                twout.Write(indent + '}');
+            }
+        }
+
+        /**
+         * Throw an exception.
+         */
+        private class OTStmtThrow: OTStmt
+        {
+            private OTOpnd value;
+            private OTDecompile decompile;
+
+            public OTStmtThrow(OTOpnd value, OTDecompile decompile)
+            {
+                this.value = value;
+                this.decompile = decompile;
+            }
+
+            public override void CountRefs()
+            {
+                value.CountRefs(false);
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                return StripStuffForTerminal(link);
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                if(value != null)
+                    value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                // throw newobj ScriptUndefinedStateException ("x")  =>  state x
+                if(value is OTOpndNewobj)
+                {
+                    OTOpndNewobj valueno = (OTOpndNewobj)value;
+                    if((valueno.ctor.DeclaringType == typeof(ScriptUndefinedStateException)) &&
+                        (valueno.args.Length == 1) && (valueno.args[0] is OTOpndString))
+                    {
+                        OTOpndString arg0 = (OTOpndString)valueno.args[0];
+                        twout.Write("state " + arg0.value + ";  /* throws undefined state exception */");
+                        return;
+                    }
+                }
+
+                // throw newobj ScriptChangeStateException (n)  =>  state n
+                if(value is OTOpndNewobj)
+                {
+                    OTOpndNewobj valueno = (OTOpndNewobj)value;
+                    if((valueno.ctor.DeclaringType == typeof(ScriptChangeStateException)) &&
+                        (valueno.args.Length == 1) && (valueno.args[0] is OTOpndInt))
+                    {
+                        OTOpndInt arg0 = (OTOpndInt)valueno.args[0];
+                        twout.Write("state " + decompile.scriptObjCode.stateNames[arg0.value] + ';');
+                        return;
+                    }
+                }
+
+                // throwing something else, output as is
+                twout.Write("throw " + value.PrintableString + ';');
+            }
+        }
+
+        /**
+         * Call with void return, or really anything that we discard the value of after computing it.
+         */
+        private class OTStmtVoid: OTStmt
+        {
+            private OTOpnd value;
+
+            public static void AddLast(OTDecompile decompile, OTOpnd value)
+            {
+                OTStmt it = OTStmtVoid.Make(value);
+                if(it != null)
+                    decompile.AddLastStmt(it);
+            }
+
+            public static OTStmt Make(OTOpnd value)
+            {
+                if(!value.HasSideEffects)
+                    return null;
+                OTStmtVoid it = new OTStmtVoid();
+                it.value = value;
+                return it;
+            }
+
+            private OTStmtVoid()
+            {
+            }
+
+            public override void CountRefs()
+            {
+                value.CountRefs(false);
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                value = value.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // strip out calls to CheckRunQuick() and CheckRunStack()
+                if(value is OTOpndCall)
+                {
+                    OTOpndCall call = (OTOpndCall)value;
+                    MethodInfo method = call.method;
+                    if((method.Name == _checkRunQuick) || (method.Name == _checkRunStack))
+                    {
+                        link.List.Remove(link);
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write(value.PrintableString + ';');
+            }
+        }
+
+        /***************************\
+         *  Structured statements  *
+        \***************************/
+
+        /**
+         * Block of statements.
+         */
+        private class OTStmtBlock: OTStmt
+        {
+            public LinkedList<OTStmt> blkstmts = new LinkedList<OTStmt>();
+
+            public override void CountRefs()
+            {
+                foreach(OTStmt stmt in blkstmts)
+                {
+                    stmt.CountRefs();
+                }
+            }
+
+            /**
+             * Scrub out all references to behind-the-scenes parts and simplify.
+             */
+            public override bool StripStuff(LinkedListNode<OTStmt> link)
+            {
+                // loop through all sub-statements to strip out behind-the-scenes references
+                bool rc = false;
+                loop:
+                for(LinkedListNode<OTStmt> stmtlink = blkstmts.First; stmtlink != null; stmtlink = stmtlink.Next)
+                {
+                    if(stmtlink.Value.StripStuff(stmtlink))
+                    {
+                        rc = true;
+                        goto loop;
+                    }
+                }
+                if(rc)
+                    return true;
+
+                // try to merge this block into outer block
+                // change:
+                //   {
+                //       ...
+                //       {          << link points here
+                //           ...
+                //       }
+                //       ...
+                //   }
+                // to:
+                //   {
+                //       ...
+                //       ...
+                //       ...
+                //   }
+                if(link != null)
+                {
+                    LinkedListNode<OTStmt> nextlink;
+                    while((nextlink = blkstmts.Last) != null)
+                    {
+                        nextlink.List.Remove(nextlink);
+                        link.List.AddAfter(link, nextlink);
+                    }
+                    link.List.Remove(link);
+                    return true;
+                }
+
+                return rc;
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = false;
+                foreach(OTStmt stmt in blkstmts)
+                {
+                    rc |= stmt.ReplaceOperand(oldopnd, newopnd);
+                }
+                return rc;
+            }
+
+            /**
+             * Check each statement in the block to see if it starts a do/for/if/while statement.
+             */
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                bool rc = false;
+                loop:
+                for(link = blkstmts.First; link != null; link = link.Next)
+                {
+                    if(link.Value.DetectDoForIfWhile(link))
+                    {
+                        rc = true;
+                        goto loop;
+                    }
+                }
+                return rc;
+            }
+
+            /**
+             * Assume we will never try to replace the block itself.
+             * But go through all our sub-ordinates statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                for(LinkedListNode<OTStmt> childlink = blkstmts.First; childlink != null; childlink = childlink.Next)
+                {
+                    childlink.Value = childlink.Value.ReplaceStatement(oldstmt, newstmt);
+                }
+                return this;
+            }
+
+            /**
+             * Print out the block including its enclosed statements.
+             */
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                switch(blkstmts.Count)
+                {
+                    case 0:
+                        {
+                            twout.Write("{ }");
+                            break;
+                        }
+                    ////case 1: {
+                    ////    blkstmts.First.Value.PrintStmt (twout, indent);
+                    ////    break;
+                    ////}
+                    default:
+                        {
+                            twout.Write('{');
+                            PrintBodyAndEnd(twout, indent);
+                            break;
+                        }
+                }
+            }
+
+            public void PrintBodyAndEnd(TextWriter twout, string indent)
+            {
+                string newindent = indent + INDENT;
+                foreach(OTStmt stmt in blkstmts)
+                {
+                    twout.Write('\n' + indent);
+                    if(!(stmt is OTStmtLabel))
+                        twout.Write(INDENT);
+                    else
+                        twout.Write(LABELINDENT);
+                    stmt.PrintStmt(twout, newindent);
+                }
+                twout.Write('\n' + indent + '}');
+            }
+        }
+
+        /**
+         * 'do' statement.
+         */
+        private class OTStmtDo: OTStmt
+        {
+            private OTOpnd dotest;
+            private OTStmtBlock dobody;
+
+            /**
+             * See if we have a do loop...
+             *   @doloop_<suffix>;     << link points here
+             *     ... <dobody> ...
+             *     [ if (dotest) ] jump doloop_<suffix>;
+             */
+            public static bool Detect(LinkedListNode<OTStmt> link)
+            {
+                // see if we have label starting with 'doloop_'
+                OTLabel looplabel = ((OTStmtLabel)link.Value).label;
+                if(!looplabel.name.StartsWith(_doLoop))
+                    return false;
+
+                // good chance we have a do loop
+                OTStmtDo it = new OTStmtDo();
+
+                // scan ahead looking for the terminating cond/jump loop
+                // also gather up the statements for the do body block
+                it.dobody = new OTStmtBlock();
+                LinkedListNode<OTStmt> nextlink;
+                for(nextlink = link.Next; nextlink != null; nextlink = nextlink.Next)
+                {
+                    OTStmt nextstmt = nextlink.Value;
+
+                    // add statement to do body
+                    it.dobody.blkstmts.AddLast(nextlink.Value);
+
+                    // check for something what jumps to loop label
+                    // that gives us the end of the loop
+                    OTStmt maybejump = nextstmt;
+                    if(nextstmt is OTStmtCond)
+                    {
+                        maybejump = ((OTStmtCond)nextstmt).stmt;
+                    }
+                    if((maybejump is OTStmtJump) && (((OTStmtJump)maybejump).label == looplabel))
+                    {
+                        break;
+                    }
+                }
+
+                // make sure we found the jump back to the loop label
+                if(nextlink == null)
+                    return false;
+
+                // remove all statements from caller's block including the continue label if any
+                // but leave the break label alone it will be removed later if unreferenced
+                // and leave the initial loop label intact for now
+                for(LinkedListNode<OTStmt> remlink = null; (remlink = link.Next) != null;)
+                {
+                    link.List.Remove(remlink);
+                    if(remlink == nextlink)
+                        break;
+                }
+
+                // take test condition from last statement of body
+                // it should be an cond/jump or just a jump to the loop label
+                LinkedListNode<OTStmt> lastlink = it.dobody.blkstmts.Last;
+                OTStmt laststmt = lastlink.Value;
+                if(laststmt is OTStmtCond)
+                {
+                    it.dotest = ((OTStmtCond)laststmt).valu;
+                }
+                else
+                {
+                    it.dotest = new OTOpndInt(1);
+                }
+                lastlink.List.Remove(lastlink);
+
+                // finally replace the loop label with the whole do statement
+                link.Value = it;
+
+                // tell caller we made a change
+                return true;
+            }
+
+            public override void CountRefs()
+            {
+                if(dotest != null)
+                    dotest.CountRefs(false);
+                if(dobody != null)
+                    dobody.CountRefs();
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return dobody.ReplaceOperand(oldopnd, newopnd);
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return dobody.DetectDoForIfWhile(link);
+            }
+
+            /**
+             * Assume we won't replace the do statement itself.
+             * But search all our sub-ordinate statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                dobody = (OTStmtBlock)dobody.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                // output do body
+                twout.Write("do ");
+                dobody.PrintStmt(twout, indent);
+
+                // output while part
+                twout.Write(" while (" + StripBrtrue(dotest).PrintableString + ");");
+            }
+        }
+
+        /**
+         * 'for' or 'while' statement.
+         */
+        private class OTStmtFor: OTStmt
+        {
+            private bool iswhile;
+            private OTOpnd fortest;
+            private OTStmtBlock forbody;
+            private OTStmt forinit;
+            private OTStmt forstep;
+
+            /**
+             * See if we have a for or while loop...
+             *     <forinit>
+             *   @forloop_<suffix>;     << link points here
+             *     [ if (<fortest>) jump forbreak_<suffix>; ]
+             *     ... <forbody> ...
+             *     jump forloop_<suffix>;
+             *   [ @forbreak_<suffix>; ]
+             */
+            public static bool Detect(LinkedListNode<OTStmt> link, bool iswhile)
+            {
+                string loopname = iswhile ? _whileLoop : _forLoop;
+                string breakname = iswhile ? _whileBreak : _forBreak;
+
+                // see if we have label starting with 'forloop_'
+                OTLabel looplabel = ((OTStmtLabel)link.Value).label;
+                if(!looplabel.name.StartsWith(loopname))
+                    return false;
+
+                // good chance we have a for loop
+                OTStmtFor it = new OTStmtFor();
+                it.iswhile = iswhile;
+
+                // all labels end with this suffix
+                string suffix = looplabel.name.Substring(loopname.Length);
+
+                // scan ahead looking for the 'jump forloop_<suffix>;' statement
+                // also gather up the statements for the for body block
+                it.forbody = new OTStmtBlock();
+                LinkedListNode<OTStmt> lastlink;
+                for(lastlink = link; (lastlink = lastlink.Next) != null;)
+                {
+
+                    // check for jump forloop that tells us where loop ends
+                    if(lastlink.Value is OTStmtJump)
+                    {
+                        OTStmtJump lastjump = (OTStmtJump)lastlink.Value;
+                        if(lastjump.label == looplabel)
+                            break;
+                    }
+
+                    // add to body block
+                    it.forbody.blkstmts.AddLast(lastlink.Value);
+                }
+
+                // make sure we found the 'jump forloop' where the for loop ends
+                if(lastlink == null)
+                    return false;
+
+                // remove all statements from caller's block including final jump
+                // but leave the loop label in place
+                for(LinkedListNode<OTStmt> nextlink = null; (nextlink = link.Next) != null;)
+                {
+                    link.List.Remove(nextlink);
+                    if(nextlink == lastlink)
+                        break;
+                }
+
+                // if statement before loop label is an assignment, use it for the init statement
+                if(!iswhile && (link.Previous != null) && (link.Previous.Value is OTStmtStore))
+                {
+                    it.forinit = link.Previous.Value;
+                    link.List.Remove(link.Previous);
+                }
+
+                // if first statement of for body is 'if (...) jump breaklabel' use it for the test value
+                if((it.forbody.blkstmts.First != null) && (it.forbody.blkstmts.First.Value is OTStmtCond))
+                {
+                    OTStmtCond condstmt = (OTStmtCond)it.forbody.blkstmts.First.Value;
+                    if((condstmt.stmt is OTStmtJump) && (((OTStmtJump)condstmt.stmt).label.name == breakname + suffix))
+                    {
+                        it.fortest = OTOpndUnOp.Make(MyOp.Brfalse, condstmt.valu);
+                        it.forbody.blkstmts.RemoveFirst();
+                    }
+                }
+
+                // if last statement of body is an assigment,
+                // use the assignment as the step statement
+                if(!iswhile && (it.forbody.blkstmts.Last != null) &&
+                        (it.forbody.blkstmts.Last.Value is OTStmtStore))
+                {
+                    LinkedListNode<OTStmt> storelink = it.forbody.blkstmts.Last;
+                    storelink.List.Remove(storelink);
+                    it.forstep = storelink.Value;
+                }
+
+                // finally replace the loop label with the whole for statement
+                link.Value = it;
+
+                // tell caller we made a change
+                return true;
+            }
+
+            public override void CountRefs()
+            {
+                if(fortest != null)
+                    fortest.CountRefs(false);
+                if(forbody != null)
+                    forbody.CountRefs();
+                if(forinit != null)
+                    forinit.CountRefs();
+                if(forstep != null)
+                    forstep.CountRefs();
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                return forbody.ReplaceOperand(oldopnd, newopnd) |
+                        ((forinit != null) && forinit.ReplaceOperand(oldopnd, newopnd)) |
+                        ((forstep != null) && forstep.ReplaceOperand(oldopnd, newopnd));
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return forbody.DetectDoForIfWhile(link) |
+                            ((forinit != null) && forinit.DetectDoForIfWhile(link)) |
+                            ((forstep != null) && forstep.DetectDoForIfWhile(link));
+            }
+
+            /**
+             * Assume we won't replace the for statement itself.
+             * But search all our sub-ordinate statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                forbody = (OTStmtBlock)forbody.ReplaceStatement(oldstmt, newstmt);
+                if(forinit != null)
+                    forinit = forinit.ReplaceStatement(oldstmt, newstmt);
+                if(forstep != null)
+                    forstep = forstep.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                if(iswhile)
+                {
+                    twout.Write("while (");
+                    if(fortest == null)
+                    {
+                        twout.Write("TRUE");
+                    }
+                    else
+                    {
+                        twout.Write(StripBrtrue(fortest).PrintableString);
+                    }
+                }
+                else
+                {
+                    twout.Write("for (");
+                    if(forinit != null)
+                    {
+                        forinit.PrintStmt(twout, indent + INDENT);
+                    }
+                    else
+                    {
+                        twout.Write(';');
+                    }
+                    if(fortest != null)
+                    {
+                        twout.Write(' ' + StripBrtrue(fortest).PrintableString);
+                    }
+                    twout.Write(';');
+                    if(forstep != null)
+                    {
+                        StringWriter sw = new StringWriter();
+                        sw.Write(' ');
+                        forstep.PrintStmt(sw, indent + INDENT);
+                        StringBuilder sb = sw.GetStringBuilder();
+                        int sl = sb.Length;
+                        if((sl > 0) && (sb[sl - 1] == ';'))
+                            sb.Remove(--sl, 1);
+                        twout.Write(sb.ToString());
+                    }
+                }
+
+                twout.Write(") ");
+                forbody.PrintStmt(twout, indent);
+            }
+        }
+
+        /**
+         * if/then/else block.
+         */
+        private class OTStmtIf: OTStmt
+        {
+            private OTOpnd testvalu;
+            private OTStmt thenstmt;
+            private OTStmt elsestmt;  // might be null
+
+            /**
+             * Try to detect a structured if statement.
+             *
+             *   if (condition) jump ifdone_<suffix>;   << link points here
+             *      ... then body ...
+             * @ifdone_<suffix>;
+             *
+             *   if (condition) jump ifelse_<suffix>;
+             *      ... then body ...
+             *   jump ifdone_<suffix>;  << optional if true body doesn't fall through
+             * @ifelse_<suffix>;
+             *      ... else body ...
+             * @ifdone_<suffix>;
+             */
+            public static bool Detect(LinkedListNode<OTStmt> link)
+            {
+                OTStmtCond condstmt = (OTStmtCond)link.Value;
+                if(!(condstmt.stmt is OTStmtJump))
+                    return false;
+
+                OTStmtJump jumpstmt = (OTStmtJump)condstmt.stmt;
+                if(jumpstmt.label.name.StartsWith(_ifDone))
+                {
+
+                    // then-only if
+
+                    // skip forward to find the ifdone_<suffix> label
+                    // also save the intervening statements for the then body
+                    OTStmtBlock thenbody;
+                    LinkedListNode<OTStmt> donelink = ScanForLabel(link, jumpstmt.label, out thenbody);
+
+                    // make sure we found matching label
+                    if(donelink == null)
+                        return false;
+
+                    // replace the jump ifdone_<suffix> with the <then body>
+                    OTStmtIf it = new OTStmtIf();
+                    it.thenstmt = thenbody;
+
+                    // replace the test value with the opposite
+                    it.testvalu = OTOpndUnOp.Make(MyOp.Brfalse, condstmt.valu);
+                    condstmt.valu = null;
+
+                    // strip out the true body statements from the main code including the ifdone_<suffix> label
+                    StripInterveningStatements(link, donelink);
+
+                    // replace the simple conditional with the if/then/else block
+                    link.Value = it;
+
+                    // tell caller we changed something
+                    return true;
+                }
+
+                if(jumpstmt.label.name.StartsWith(_ifElse))
+                {
+                    string suffix = jumpstmt.label.name.Substring(_ifElse.Length);
+
+                    // if/then/else
+                    OTStmtIf it = new OTStmtIf();
+
+                    // skip forward to find the ifelse_<suffix> label
+                    // also save the intervening statements for the true body
+                    OTStmtBlock thenbody;
+                    LinkedListNode<OTStmt> elselink = ScanForLabel(link, jumpstmt.label, out thenbody);
+
+                    // make sure we found matching label
+                    if(elselink != null)
+                    {
+
+                        // the last statement of the then body might be a jump ifdone_<suffix>
+                        LinkedListNode<OTStmt> lastthenlink = thenbody.blkstmts.Last;
+                        if((lastthenlink != null) && (lastthenlink.Value is OTStmtJump))
+                        {
+                            OTStmtJump jumpifdone = (OTStmtJump)lastthenlink.Value;
+                            if(jumpifdone.label.name == _ifDone + suffix)
+                            {
+
+                                lastthenlink.List.Remove(lastthenlink);
+
+                                // skip forward to find the ifdone_<suffix> label
+                                // also save the intervening statements for the else body
+                                OTStmtBlock elsebody;
+                                LinkedListNode<OTStmt> donelink = ScanForLabel(elselink, jumpifdone.label, out elsebody);
+                                if(donelink != null)
+                                {
+
+                                    // replace the jump ifdone_<suffix> with the <true body>
+                                    it.thenstmt = thenbody;
+
+                                    // save the else body as well
+                                    it.elsestmt = elsebody;
+
+                                    // replace the test value with the opposite
+                                    it.testvalu = OTOpndUnOp.Make(MyOp.Brfalse, condstmt.valu);
+                                    condstmt.valu = null;
+
+                                    // strip out the true and else body statements from the main code including the ifdone_<suffix> label
+                                    StripInterveningStatements(link, donelink);
+
+                                    // replace the simple conditional with the if/then/else block
+                                    link.Value = it;
+
+                                    // tell caller we changed something
+                                    return true;
+                                }
+                            }
+                        }
+
+                        // missing the jump _ifDone_<suffix>, so make it a simple if/then
+                        //   if (condition) jump ifelse_<suffix>;   << link
+                        //      ... then body ...                   << encapsulated in block thenbody
+                        // @ifelse_<suffix>;                        << elselink
+                        //      ... else body ...                   << still inline and leave it there
+                        // @ifdone_<suffix>;                        << strip this out
+
+                        // replace the jump ifelse_<suffix> with the <true body>
+                        it.thenstmt = thenbody;
+
+                        // replace the test value with the opposite
+                        it.testvalu = OTOpndUnOp.Make(MyOp.Brfalse, condstmt.valu);
+                        condstmt.valu = null;
+
+                        // strip out the then body statements from the main code including the ifelse_<suffix> label
+                        StripInterveningStatements(link, elselink);
+
+                        // there's a dangling unused ifdone_<suffix> label ahead that has to be stripped
+                        for(LinkedListNode<OTStmt> donelink = link; (donelink = donelink.Next) != null;)
+                        {
+                            if((donelink.Value is OTStmtLabel) && (((OTStmtLabel)donelink.Value).label.name == _ifDone + suffix))
+                            {
+                                donelink.List.Remove(donelink);
+                                break;
+                            }
+                        }
+
+                        // replace the simple conditional with the if/then/else block
+                        link.Value = it;
+
+                        // tell caller we changed something
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            private OTStmtIf()
+            {
+            }
+
+            public override void CountRefs()
+            {
+                if(testvalu != null)
+                    testvalu.CountRefs(false);
+                if(thenstmt != null)
+                    thenstmt.CountRefs();
+                if(elsestmt != null)
+                    elsestmt.CountRefs();
+            }
+
+            public override bool ReplaceOperand(OTOpnd oldopnd, OTOpnd newopnd)
+            {
+                bool rc = thenstmt.ReplaceOperand(oldopnd, newopnd);
+                testvalu = testvalu.ReplaceOperand(oldopnd, newopnd, ref rc);
+                return rc;
+            }
+
+            public override bool DetectDoForIfWhile(LinkedListNode<OTStmt> link)
+            {
+                return ((thenstmt != null) && thenstmt.DetectDoForIfWhile(link)) |
+                       ((elsestmt != null) && elsestmt.DetectDoForIfWhile(link));
+            }
+
+            /**
+             * Assume we won't replace the if statement itself.
+             * But search all our sub-ordinate statements.
+             */
+            public override OTStmt ReplaceStatement(OTStmt oldstmt, OTStmt newstmt)
+            {
+                thenstmt = thenstmt.ReplaceStatement(oldstmt, newstmt);
+                if(elsestmt != null)
+                    elsestmt = elsestmt.ReplaceStatement(oldstmt, newstmt);
+                return this;
+            }
+
+            public override void PrintStmt(TextWriter twout, string indent)
+            {
+                twout.Write("if (" + StripBrtrue(testvalu).PrintableString + ") ");
+                OTStmt thenst = ReduceStmtBody(thenstmt, false);
+                thenst.PrintStmt(twout, indent);
+                if(elsestmt != null)
+                {
+                    twout.Write('\n' + indent + "else ");
+                    OTStmt elsest = ReduceStmtBody(elsestmt, true);
+                    elsest.PrintStmt(twout, indent);
+                }
+            }
+
+            // strip block off a single jump so it prints inline instead of with braces around it
+            // also, if this is part of else, strip block for ifs to make else if statement
+            private static OTStmt ReduceStmtBody(OTStmt statement, bool stripif)
+            {
+                OTStmt onestmt = statement;
+                if((onestmt is OTStmtBlock) && (((OTStmtBlock)onestmt).blkstmts.Count == 1))
+                {
+                    onestmt = ((OTStmtBlock)onestmt).blkstmts.First.Value;
+                    if((onestmt is OTStmtJump) || (stripif && (onestmt is OTStmtIf)))
+                    {
+                        return onestmt;
+                    }
+                }
+                return statement;
+            }
+
+            /**
+             * Scan forward for a given label definition.
+             * Put intervening statements in a statement block.
+             * @param link = start scanning after this statement
+             * @param label = look for this label definition
+             * @param block = where to return intervening statement block
+             * @returns null: label definition not found
+             *          else: label definition statement
+             */
+            private static LinkedListNode<OTStmt> ScanForLabel(LinkedListNode<OTStmt> link,
+                        OTLabel label, out OTStmtBlock block)
+            {
+                block = new OTStmtBlock();
+                while((link = link.Next) != null)
+                {
+                    if(link.Value is OTStmtLabel)
+                    {
+                        if(((OTStmtLabel)link.Value).label == label)
+                            break;
+                    }
+                    block.blkstmts.AddLast(link.Value);
+                }
+                return link;
+            }
+
+            /**
+             * Strip statements after link up to and including donelink.
+             */
+            private static void StripInterveningStatements(LinkedListNode<OTStmt> link, LinkedListNode<OTStmt> donelink)
+            {
+                LinkedListNode<OTStmt> striplink;
+                do
+                {
+                    striplink = link.Next;
+                    striplink.List.Remove(striplink);
+                } while(striplink != donelink);
+            }
+        }
+
+        private class MyOp
+        {
+            public int index;
+            public OpCode sysop;
+            public string name;
+            public string source;
+
+            private static Dictionary<string, MyOp> myopsbyname = new Dictionary<string, MyOp>();
+            private static int nextindex = 0;
+
+            public MyOp(OpCode sysop)
+            {
+                this.index = nextindex++;
+                this.sysop = sysop;
+                this.name = sysop.Name;
+                myopsbyname.Add(name, this);
+            }
+
+            public MyOp(OpCode sysop, string source)
+            {
+                this.index = nextindex++;
+                this.sysop = sysop;
+                this.name = sysop.Name;
+                this.source = source;
+                myopsbyname.Add(name, this);
+            }
+
+            public MyOp(string name)
+            {
+                this.index = nextindex++;
+                this.name = name;
+                myopsbyname.Add(name, this);
+            }
+
+            public MyOp(string name, string source)
+            {
+                this.index = nextindex++;
+                this.name = name;
+                this.source = source;
+                myopsbyname.Add(name, this);
+            }
+
+            public static MyOp GetByName(string name)
+            {
+                return myopsbyname[name];
+            }
+
+            public override string ToString()
+            {
+                return name;
+            }
+
+            // these copied from OpCodes.cs
+            public static readonly MyOp Nop = new MyOp(OpCodes.Nop);
+            public static readonly MyOp Break = new MyOp(OpCodes.Break);
+            public static readonly MyOp Ldarg_0 = new MyOp(OpCodes.Ldarg_0);
+            public static readonly MyOp Ldarg_1 = new MyOp(OpCodes.Ldarg_1);
+            public static readonly MyOp Ldarg_2 = new MyOp(OpCodes.Ldarg_2);
+            public static readonly MyOp Ldarg_3 = new MyOp(OpCodes.Ldarg_3);
+            public static readonly MyOp Ldloc_0 = new MyOp(OpCodes.Ldloc_0);
+            public static readonly MyOp Ldloc_1 = new MyOp(OpCodes.Ldloc_1);
+            public static readonly MyOp Ldloc_2 = new MyOp(OpCodes.Ldloc_2);
+            public static readonly MyOp Ldloc_3 = new MyOp(OpCodes.Ldloc_3);
+            public static readonly MyOp Stloc_0 = new MyOp(OpCodes.Stloc_0);
+            public static readonly MyOp Stloc_1 = new MyOp(OpCodes.Stloc_1);
+            public static readonly MyOp Stloc_2 = new MyOp(OpCodes.Stloc_2);
+            public static readonly MyOp Stloc_3 = new MyOp(OpCodes.Stloc_3);
+            public static readonly MyOp Ldarg_S = new MyOp(OpCodes.Ldarg_S);
+            public static readonly MyOp Ldarga_S = new MyOp(OpCodes.Ldarga_S);
+            public static readonly MyOp Starg_S = new MyOp(OpCodes.Starg_S);
+            public static readonly MyOp Ldloc_S = new MyOp(OpCodes.Ldloc_S);
+            public static readonly MyOp Ldloca_S = new MyOp(OpCodes.Ldloca_S);
+            public static readonly MyOp Stloc_S = new MyOp(OpCodes.Stloc_S);
+            public static readonly MyOp Ldnull = new MyOp(OpCodes.Ldnull);
+            public static readonly MyOp Ldc_I4_M1 = new MyOp(OpCodes.Ldc_I4_M1);
+            public static readonly MyOp Ldc_I4_0 = new MyOp(OpCodes.Ldc_I4_0);
+            public static readonly MyOp Ldc_I4_1 = new MyOp(OpCodes.Ldc_I4_1);
+            public static readonly MyOp Ldc_I4_2 = new MyOp(OpCodes.Ldc_I4_2);
+            public static readonly MyOp Ldc_I4_3 = new MyOp(OpCodes.Ldc_I4_3);
+            public static readonly MyOp Ldc_I4_4 = new MyOp(OpCodes.Ldc_I4_4);
+            public static readonly MyOp Ldc_I4_5 = new MyOp(OpCodes.Ldc_I4_5);
+            public static readonly MyOp Ldc_I4_6 = new MyOp(OpCodes.Ldc_I4_6);
+            public static readonly MyOp Ldc_I4_7 = new MyOp(OpCodes.Ldc_I4_7);
+            public static readonly MyOp Ldc_I4_8 = new MyOp(OpCodes.Ldc_I4_8);
+            public static readonly MyOp Ldc_I4_S = new MyOp(OpCodes.Ldc_I4_S);
+            public static readonly MyOp Ldc_I4 = new MyOp(OpCodes.Ldc_I4);
+            public static readonly MyOp Ldc_I8 = new MyOp(OpCodes.Ldc_I8);
+            public static readonly MyOp Ldc_R4 = new MyOp(OpCodes.Ldc_R4);
+            public static readonly MyOp Ldc_R8 = new MyOp(OpCodes.Ldc_R8);
+            public static readonly MyOp Dup = new MyOp(OpCodes.Dup);
+            public static readonly MyOp Pop = new MyOp(OpCodes.Pop);
+            public static readonly MyOp Jmp = new MyOp(OpCodes.Jmp);
+            public static readonly MyOp Call = new MyOp(OpCodes.Call);
+            public static readonly MyOp Calli = new MyOp(OpCodes.Calli);
+            public static readonly MyOp Ret = new MyOp(OpCodes.Ret);
+            public static readonly MyOp Br_S = new MyOp(OpCodes.Br_S);
+            public static readonly MyOp Brfalse_S = new MyOp(OpCodes.Brfalse_S);
+            public static readonly MyOp Brtrue_S = new MyOp(OpCodes.Brtrue_S);
+            public static readonly MyOp Beq_S = new MyOp(OpCodes.Beq_S, "==");
+            public static readonly MyOp Bge_S = new MyOp(OpCodes.Bge_S, ">=");
+            public static readonly MyOp Bgt_S = new MyOp(OpCodes.Bgt_S, ">");
+            public static readonly MyOp Ble_S = new MyOp(OpCodes.Ble_S, "<=");
+            public static readonly MyOp Blt_S = new MyOp(OpCodes.Blt_S, "<");
+            public static readonly MyOp Bne_Un_S = new MyOp(OpCodes.Bne_Un_S, "!=");
+            public static readonly MyOp Bge_Un_S = new MyOp(OpCodes.Bge_Un_S);
+            public static readonly MyOp Bgt_Un_S = new MyOp(OpCodes.Bgt_Un_S);
+            public static readonly MyOp Ble_Un_S = new MyOp(OpCodes.Ble_Un_S);
+            public static readonly MyOp Blt_Un_S = new MyOp(OpCodes.Blt_Un_S);
+            public static readonly MyOp Br = new MyOp(OpCodes.Br);
+            public static readonly MyOp Brfalse = new MyOp(OpCodes.Brfalse, "!");
+            public static readonly MyOp Brtrue = new MyOp(OpCodes.Brtrue, "!!");
+            public static readonly MyOp Beq = new MyOp(OpCodes.Beq, "==");
+            public static readonly MyOp Bge = new MyOp(OpCodes.Bge, ">=");
+            public static readonly MyOp Bgt = new MyOp(OpCodes.Bgt, ">");
+            public static readonly MyOp Ble = new MyOp(OpCodes.Ble, "<=");
+            public static readonly MyOp Blt = new MyOp(OpCodes.Blt, "<");
+            public static readonly MyOp Bne_Un = new MyOp(OpCodes.Bne_Un, "!=");
+            public static readonly MyOp Bge_Un = new MyOp(OpCodes.Bge_Un);
+            public static readonly MyOp Bgt_Un = new MyOp(OpCodes.Bgt_Un);
+            public static readonly MyOp Ble_Un = new MyOp(OpCodes.Ble_Un);
+            public static readonly MyOp Blt_Un = new MyOp(OpCodes.Blt_Un);
+            public static readonly MyOp Switch = new MyOp(OpCodes.Switch);
+            public static readonly MyOp Ldind_I1 = new MyOp(OpCodes.Ldind_I1);
+            public static readonly MyOp Ldind_U1 = new MyOp(OpCodes.Ldind_U1);
+            public static readonly MyOp Ldind_I2 = new MyOp(OpCodes.Ldind_I2);
+            public static readonly MyOp Ldind_U2 = new MyOp(OpCodes.Ldind_U2);
+            public static readonly MyOp Ldind_I4 = new MyOp(OpCodes.Ldind_I4);
+            public static readonly MyOp Ldind_U4 = new MyOp(OpCodes.Ldind_U4);
+            public static readonly MyOp Ldind_I8 = new MyOp(OpCodes.Ldind_I8);
+            public static readonly MyOp Ldind_I = new MyOp(OpCodes.Ldind_I);
+            public static readonly MyOp Ldind_R4 = new MyOp(OpCodes.Ldind_R4);
+            public static readonly MyOp Ldind_R8 = new MyOp(OpCodes.Ldind_R8);
+            public static readonly MyOp Ldind_Ref = new MyOp(OpCodes.Ldind_Ref);
+            public static readonly MyOp Stind_Ref = new MyOp(OpCodes.Stind_Ref);
+            public static readonly MyOp Stind_I1 = new MyOp(OpCodes.Stind_I1);
+            public static readonly MyOp Stind_I2 = new MyOp(OpCodes.Stind_I2);
+            public static readonly MyOp Stind_I4 = new MyOp(OpCodes.Stind_I4);
+            public static readonly MyOp Stind_I8 = new MyOp(OpCodes.Stind_I8);
+            public static readonly MyOp Stind_R4 = new MyOp(OpCodes.Stind_R4);
+            public static readonly MyOp Stind_R8 = new MyOp(OpCodes.Stind_R8);
+            public static readonly MyOp Add = new MyOp(OpCodes.Add, "+");
+            public static readonly MyOp Sub = new MyOp(OpCodes.Sub, "-");
+            public static readonly MyOp Mul = new MyOp(OpCodes.Mul, "*");
+            public static readonly MyOp Div = new MyOp(OpCodes.Div, "/");
+            public static readonly MyOp Div_Un = new MyOp(OpCodes.Div_Un);
+            public static readonly MyOp Rem = new MyOp(OpCodes.Rem, "%");
+            public static readonly MyOp Rem_Un = new MyOp(OpCodes.Rem_Un);
+            public static readonly MyOp And = new MyOp(OpCodes.And, "&");
+            public static readonly MyOp Or = new MyOp(OpCodes.Or, "|");
+            public static readonly MyOp Xor = new MyOp(OpCodes.Xor, "^");
+            public static readonly MyOp Shl = new MyOp(OpCodes.Shl, "<<");
+            public static readonly MyOp Shr = new MyOp(OpCodes.Shr, ">>");
+            public static readonly MyOp Shr_Un = new MyOp(OpCodes.Shr_Un);
+            public static readonly MyOp Neg = new MyOp(OpCodes.Neg, "-");
+            public static readonly MyOp Not = new MyOp(OpCodes.Not, "~");
+            public static readonly MyOp Conv_I1 = new MyOp(OpCodes.Conv_I1);
+            public static readonly MyOp Conv_I2 = new MyOp(OpCodes.Conv_I2);
+            public static readonly MyOp Conv_I4 = new MyOp(OpCodes.Conv_I4);
+            public static readonly MyOp Conv_I8 = new MyOp(OpCodes.Conv_I8);
+            public static readonly MyOp Conv_R4 = new MyOp(OpCodes.Conv_R4);
+            public static readonly MyOp Conv_R8 = new MyOp(OpCodes.Conv_R8);
+            public static readonly MyOp Conv_U4 = new MyOp(OpCodes.Conv_U4);
+            public static readonly MyOp Conv_U8 = new MyOp(OpCodes.Conv_U8);
+            public static readonly MyOp Callvirt = new MyOp(OpCodes.Callvirt);
+            public static readonly MyOp Cpobj = new MyOp(OpCodes.Cpobj);
+            public static readonly MyOp Ldobj = new MyOp(OpCodes.Ldobj);
+            public static readonly MyOp Ldstr = new MyOp(OpCodes.Ldstr);
+            public static readonly MyOp Newobj = new MyOp(OpCodes.Newobj);
+            public static readonly MyOp Castclass = new MyOp(OpCodes.Castclass);
+            public static readonly MyOp Isinst = new MyOp(OpCodes.Isinst);
+            public static readonly MyOp Conv_R_Un = new MyOp(OpCodes.Conv_R_Un);
+            public static readonly MyOp Unbox = new MyOp(OpCodes.Unbox);
+            public static readonly MyOp Throw = new MyOp(OpCodes.Throw);
+            public static readonly MyOp Ldfld = new MyOp(OpCodes.Ldfld);
+            public static readonly MyOp Ldflda = new MyOp(OpCodes.Ldflda);
+            public static readonly MyOp Stfld = new MyOp(OpCodes.Stfld);
+            public static readonly MyOp Ldsfld = new MyOp(OpCodes.Ldsfld);
+            public static readonly MyOp Ldsflda = new MyOp(OpCodes.Ldsflda);
+            public static readonly MyOp Stsfld = new MyOp(OpCodes.Stsfld);
+            public static readonly MyOp Stobj = new MyOp(OpCodes.Stobj);
+            public static readonly MyOp Conv_Ovf_I1_Un = new MyOp(OpCodes.Conv_Ovf_I1_Un);
+            public static readonly MyOp Conv_Ovf_I2_Un = new MyOp(OpCodes.Conv_Ovf_I2_Un);
+            public static readonly MyOp Conv_Ovf_I4_Un = new MyOp(OpCodes.Conv_Ovf_I4_Un);
+            public static readonly MyOp Conv_Ovf_I8_Un = new MyOp(OpCodes.Conv_Ovf_I8_Un);
+            public static readonly MyOp Conv_Ovf_U1_Un = new MyOp(OpCodes.Conv_Ovf_U1_Un);
+            public static readonly MyOp Conv_Ovf_U2_Un = new MyOp(OpCodes.Conv_Ovf_U2_Un);
+            public static readonly MyOp Conv_Ovf_U4_Un = new MyOp(OpCodes.Conv_Ovf_U4_Un);
+            public static readonly MyOp Conv_Ovf_U8_Un = new MyOp(OpCodes.Conv_Ovf_U8_Un);
+            public static readonly MyOp Conv_Ovf_I_Un = new MyOp(OpCodes.Conv_Ovf_I_Un);
+            public static readonly MyOp Conv_Ovf_U_Un = new MyOp(OpCodes.Conv_Ovf_U_Un);
+            public static readonly MyOp Box = new MyOp(OpCodes.Box);
+            public static readonly MyOp Newarr = new MyOp(OpCodes.Newarr);
+            public static readonly MyOp Ldlen = new MyOp(OpCodes.Ldlen);
+            public static readonly MyOp Ldelema = new MyOp(OpCodes.Ldelema);
+            public static readonly MyOp Ldelem_I1 = new MyOp(OpCodes.Ldelem_I1);
+            public static readonly MyOp Ldelem_U1 = new MyOp(OpCodes.Ldelem_U1);
+            public static readonly MyOp Ldelem_I2 = new MyOp(OpCodes.Ldelem_I2);
+            public static readonly MyOp Ldelem_U2 = new MyOp(OpCodes.Ldelem_U2);
+            public static readonly MyOp Ldelem_I4 = new MyOp(OpCodes.Ldelem_I4);
+            public static readonly MyOp Ldelem_U4 = new MyOp(OpCodes.Ldelem_U4);
+            public static readonly MyOp Ldelem_I8 = new MyOp(OpCodes.Ldelem_I8);
+            public static readonly MyOp Ldelem_I = new MyOp(OpCodes.Ldelem_I);
+            public static readonly MyOp Ldelem_R4 = new MyOp(OpCodes.Ldelem_R4);
+            public static readonly MyOp Ldelem_R8 = new MyOp(OpCodes.Ldelem_R8);
+            public static readonly MyOp Ldelem_Ref = new MyOp(OpCodes.Ldelem_Ref);
+            public static readonly MyOp Stelem_I = new MyOp(OpCodes.Stelem_I);
+            public static readonly MyOp Stelem_I1 = new MyOp(OpCodes.Stelem_I1);
+            public static readonly MyOp Stelem_I2 = new MyOp(OpCodes.Stelem_I2);
+            public static readonly MyOp Stelem_I4 = new MyOp(OpCodes.Stelem_I4);
+            public static readonly MyOp Stelem_I8 = new MyOp(OpCodes.Stelem_I8);
+            public static readonly MyOp Stelem_R4 = new MyOp(OpCodes.Stelem_R4);
+            public static readonly MyOp Stelem_R8 = new MyOp(OpCodes.Stelem_R8);
+            public static readonly MyOp Stelem_Ref = new MyOp(OpCodes.Stelem_Ref);
+            public static readonly MyOp Ldelem = new MyOp(OpCodes.Ldelem);
+            public static readonly MyOp Stelem = new MyOp(OpCodes.Stelem);
+            public static readonly MyOp Unbox_Any = new MyOp(OpCodes.Unbox_Any);
+            public static readonly MyOp Conv_Ovf_I1 = new MyOp(OpCodes.Conv_Ovf_I1);
+            public static readonly MyOp Conv_Ovf_U1 = new MyOp(OpCodes.Conv_Ovf_U1);
+            public static readonly MyOp Conv_Ovf_I2 = new MyOp(OpCodes.Conv_Ovf_I2);
+            public static readonly MyOp Conv_Ovf_U2 = new MyOp(OpCodes.Conv_Ovf_U2);
+            public static readonly MyOp Conv_Ovf_I4 = new MyOp(OpCodes.Conv_Ovf_I4);
+            public static readonly MyOp Conv_Ovf_U4 = new MyOp(OpCodes.Conv_Ovf_U4);
+            public static readonly MyOp Conv_Ovf_I8 = new MyOp(OpCodes.Conv_Ovf_I8);
+            public static readonly MyOp Conv_Ovf_U8 = new MyOp(OpCodes.Conv_Ovf_U8);
+            public static readonly MyOp Refanyval = new MyOp(OpCodes.Refanyval);
+            public static readonly MyOp Ckfinite = new MyOp(OpCodes.Ckfinite);
+            public static readonly MyOp Mkrefany = new MyOp(OpCodes.Mkrefany);
+            public static readonly MyOp Ldtoken = new MyOp(OpCodes.Ldtoken);
+            public static readonly MyOp Conv_U2 = new MyOp(OpCodes.Conv_U2);
+            public static readonly MyOp Conv_U1 = new MyOp(OpCodes.Conv_U1);
+            public static readonly MyOp Conv_I = new MyOp(OpCodes.Conv_I);
+            public static readonly MyOp Conv_Ovf_I = new MyOp(OpCodes.Conv_Ovf_I);
+            public static readonly MyOp Conv_Ovf_U = new MyOp(OpCodes.Conv_Ovf_U);
+            public static readonly MyOp Add_Ovf = new MyOp(OpCodes.Add_Ovf);
+            public static readonly MyOp Add_Ovf_Un = new MyOp(OpCodes.Add_Ovf_Un);
+            public static readonly MyOp Mul_Ovf = new MyOp(OpCodes.Mul_Ovf);
+            public static readonly MyOp Mul_Ovf_Un = new MyOp(OpCodes.Mul_Ovf_Un);
+            public static readonly MyOp Sub_Ovf = new MyOp(OpCodes.Sub_Ovf);
+            public static readonly MyOp Sub_Ovf_Un = new MyOp(OpCodes.Sub_Ovf_Un);
+            public static readonly MyOp Endfinally = new MyOp(OpCodes.Endfinally);
+            public static readonly MyOp Leave = new MyOp(OpCodes.Leave);
+            public static readonly MyOp Leave_S = new MyOp(OpCodes.Leave_S);
+            public static readonly MyOp Stind_I = new MyOp(OpCodes.Stind_I);
+            public static readonly MyOp Conv_U = new MyOp(OpCodes.Conv_U);
+            public static readonly MyOp Prefix7 = new MyOp(OpCodes.Prefix7);
+            public static readonly MyOp Prefix6 = new MyOp(OpCodes.Prefix6);
+            public static readonly MyOp Prefix5 = new MyOp(OpCodes.Prefix5);
+            public static readonly MyOp Prefix4 = new MyOp(OpCodes.Prefix4);
+            public static readonly MyOp Prefix3 = new MyOp(OpCodes.Prefix3);
+            public static readonly MyOp Prefix2 = new MyOp(OpCodes.Prefix2);
+            public static readonly MyOp Prefix1 = new MyOp(OpCodes.Prefix1);
+            public static readonly MyOp Prefixref = new MyOp(OpCodes.Prefixref);
+            public static readonly MyOp Arglist = new MyOp(OpCodes.Arglist);
+            public static readonly MyOp Ceq = new MyOp(OpCodes.Ceq, "==");
+            public static readonly MyOp Cgt = new MyOp(OpCodes.Cgt, ">");
+            public static readonly MyOp Cgt_Un = new MyOp(OpCodes.Cgt_Un);
+            public static readonly MyOp Clt = new MyOp(OpCodes.Clt, "<");
+            public static readonly MyOp Clt_Un = new MyOp(OpCodes.Clt_Un);
+            public static readonly MyOp Ldftn = new MyOp(OpCodes.Ldftn);
+            public static readonly MyOp Ldvirtftn = new MyOp(OpCodes.Ldvirtftn);
+            public static readonly MyOp Ldarg = new MyOp(OpCodes.Ldarg);
+            public static readonly MyOp Ldarga = new MyOp(OpCodes.Ldarga);
+            public static readonly MyOp Starg = new MyOp(OpCodes.Starg);
+            public static readonly MyOp Ldloc = new MyOp(OpCodes.Ldloc);
+            public static readonly MyOp Ldloca = new MyOp(OpCodes.Ldloca);
+            public static readonly MyOp Stloc = new MyOp(OpCodes.Stloc);
+            public static readonly MyOp Localloc = new MyOp(OpCodes.Localloc);
+            public static readonly MyOp Endfilter = new MyOp(OpCodes.Endfilter);
+            public static readonly MyOp Unaligned = new MyOp(OpCodes.Unaligned);
+            public static readonly MyOp Volatile = new MyOp(OpCodes.Volatile);
+            public static readonly MyOp Tailcall = new MyOp(OpCodes.Tailcall);
+            public static readonly MyOp Initobj = new MyOp(OpCodes.Initobj);
+            public static readonly MyOp Constrained = new MyOp(OpCodes.Constrained);
+            public static readonly MyOp Cpblk = new MyOp(OpCodes.Cpblk);
+            public static readonly MyOp Initblk = new MyOp(OpCodes.Initblk);
+            public static readonly MyOp Rethrow = new MyOp(OpCodes.Rethrow);
+            public static readonly MyOp Sizeof = new MyOp(OpCodes.Sizeof);
+            public static readonly MyOp Refanytype = new MyOp(OpCodes.Refanytype);
+            public static readonly MyOp Readonly = new MyOp(OpCodes.Readonly);
+
+            // used internally
+            public static readonly MyOp Cge = new MyOp("cge", ">=");
+            public static readonly MyOp Cle = new MyOp("cle", "<=");
+            public static readonly MyOp Cne = new MyOp("cne", "!=");
+        }
+    }
+}

+ 60 - 44
OpenSim/Region/ScriptEngine/XMREngine/XMRSDTypeClObj.cs → OpenSim/Region/ScriptEngine/YEngine/XMRSDTypeClObj.cs

@@ -36,7 +36,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
 
-namespace OpenSim.Region.ScriptEngine.XMREngine
+namespace OpenSim.Region.ScriptEngine.Yengine
 {
     public class XMRSDTypeClObj
     {
@@ -56,7 +56,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * Our VTable array, used for calling virtual functions.
          * And ITable array, used for calling our implementation of interface functions.
          */
-        public Delegate[]   sdtcVTable;
+        public Delegate[] sdtcVTable;
         public Delegate[][] sdtcITable;
 
         /*
@@ -69,10 +69,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Called by script's $new() to initialize a new object.
          */
-        public XMRSDTypeClObj (XMRInstAbstract inst, int classindex)
+        public XMRSDTypeClObj(XMRInstAbstract inst, int classindex)
         {
-            Construct (inst, classindex);
-            instVars.AllocVarArrays (sdtcClass.instSizes);
+            Construct(inst, classindex);
+            instVars.AllocVarArrays(sdtcClass.instSizes);
         }
 
         /**
@@ -81,26 +81,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param classindex = which script-defined type class this object is an onstance of
          * @returns with the vtables filled in
          */
-        private void Construct (XMRInstAbstract inst, int classindex)
+        private void Construct(XMRInstAbstract inst, int classindex)
         {
             Delegate[] thisMid = null;
             TokenDeclSDTypeClass clas = (TokenDeclSDTypeClass)inst.m_ObjCode.sdObjTypesIndx[classindex];
 
-            xmrInst   = inst;
+            xmrInst = inst;
             sdtcClass = clas;
-            instVars  = new XMRInstArrays (inst);
+            instVars = new XMRInstArrays(inst);
 
             /*
              * VTable consists of delegates built from DynamicMethods and the 'this' pointer.
              * Yes, yes, lots of shitty little mallocs.
              */
             DynamicMethod[] vDynMeths = clas.vDynMeths;
-            if (vDynMeths != null) {
+            if(vDynMeths != null)
+            {
                 int n = vDynMeths.Length;
                 Type[] vMethTypes = clas.vMethTypes;
                 sdtcVTable = new Delegate[n];
-                for (int i = 0; i < n; i ++) {
-                    sdtcVTable[i] = vDynMeths[i].CreateDelegate (vMethTypes[i], this);
+                for(int i = 0; i < n; i++)
+                {
+                    sdtcVTable[i] = vDynMeths[i].CreateDelegate(vMethTypes[i], this);
                 }
             }
 
@@ -114,33 +116,40 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
              * So we end up with this:
              *    sdtcITable[interfacenumber][methodofintfnumber] = delegate of this.ourimplementationofinterfacesmethod
              */
-            if (clas.iDynMeths != null) {
+            if(clas.iDynMeths != null)
+            {
                 int nIFaces = clas.iDynMeths.Length;
                 sdtcITable = new Delegate[nIFaces][];
-                for (int i = 0; i < nIFaces; i ++) {
+                for(int i = 0; i < nIFaces; i++)
+                {
 
                     // get vector of entrypoints of our instance methods that implement that interface
                     DynamicMethod[] iDynMeths = clas.iDynMeths[i];
-                    Type[]         iMethTypes = clas.iMethTypes[i];
+                    Type[] iMethTypes = clas.iMethTypes[i];
 
                     // allocate an array with a slot for each method the interface defines
                     int nMeths = iDynMeths.Length;
                     Delegate[] ivec;
-                    if (nMeths > 0) {
+                    if(nMeths > 0)
+                    {
                         // fill in the array with delegates that reference back to this class instance
                         ivec = new Delegate[nMeths];
-                        for (int j = 0; j < nMeths; j ++) {
-                            ivec[j] = iDynMeths[j].CreateDelegate (iMethTypes[j], this);
+                        for(int j = 0; j < nMeths; j++)
+                        {
+                            ivec[j] = iDynMeths[j].CreateDelegate(iMethTypes[j], this);
                         }
-                    } else {
+                    }
+                    else
+                    {
                         // just a marker interface with no methods,
                         // allocate a one-element array and fill
                         // with a dummy entry.  this will allow casting
                         // back to the original class instance (this)
                         // by reading Target of entry 0.
-                        if (thisMid == null) {
+                        if(thisMid == null)
+                        {
                             thisMid = new Delegate[1];
-                            thisMid[0] = markerInterfaceDummy.CreateDelegate (typeof (MarkerInterfaceDummy), this);
+                            thisMid[0] = markerInterfaceDummy.CreateDelegate(typeof(MarkerInterfaceDummy), this);
                         }
                         ivec = thisMid;
                     }
@@ -151,13 +160,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
             }
         }
 
-        private delegate void MarkerInterfaceDummy ();
-        private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy ();
-        private static DynamicMethod MakeMarkerInterfaceDummy ()
+        private delegate void MarkerInterfaceDummy();
+        private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy();
+        private static DynamicMethod MakeMarkerInterfaceDummy()
         {
-            DynamicMethod dm = new DynamicMethod ("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof (XMRSDTypeClObj) });
-            ILGenerator ilGen = dm.GetILGenerator ();
-            ilGen.Emit (OpCodes.Ret);
+            DynamicMethod dm = new DynamicMethod("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof(XMRSDTypeClObj) });
+            ILGenerator ilGen = dm.GetILGenerator();
+            ilGen.Emit(OpCodes.Ret);
             return dm;
         }
 
@@ -168,9 +177,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param classindex = what class those implementations are supposedly part of
          * @returns original script-defined class object
          */
-        public static XMRSDTypeClObj CastIFace2Class (Delegate[] da, int classindex)
+        public static XMRSDTypeClObj CastIFace2Class(Delegate[] da, int classindex)
         {
-            return CastClass2Class (da[0].Target, classindex);
+            return CastClass2Class(da[0].Target, classindex);
         }
 
         /**
@@ -179,13 +188,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param classindex = script-defined class to cast it to
          * @returns ob is a valid instance of classindex; else exception thrown
          */
-        public static XMRSDTypeClObj CastClass2Class (object ob, int classindex)
+        public static XMRSDTypeClObj CastClass2Class(object ob, int classindex)
         {
             /*
              * Let mono check to see if we at least have an XMRSDTypeClObj.
              */
             XMRSDTypeClObj ci = (XMRSDTypeClObj)ob;
-            if (ci != null) {
+            if(ci != null)
+            {
 
                 /*
                  * This is the target class, ie, what we are hoping the object can cast to.
@@ -197,9 +207,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
                  * If we find the target class along the way, the cast is valid.
                  * If we run off the end of the root, the cast is not valid.
                  */
-                for (TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends) {
-                    if (ac == null) throw new InvalidCastException ("invalid cast from " + ci.sdtcClass.longName.val + 
-                                                                                  " to " + tc.longName.val);
+                for(TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends)
+                {
+                    if(ac == null)
+                        throw new InvalidCastException("invalid cast from " + ci.sdtcClass.longName.val +
+                                                                      " to " + tc.longName.val);
                 }
 
                 /*
@@ -215,14 +227,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
          * @param ob = object to be cast of unknown type
          * @returns ob cast to the interface type
          */
-        public static Delegate[] CastObj2IFace (object ob, string ifacename)
+        public static Delegate[] CastObj2IFace(object ob, string ifacename)
         {
-            if (ob == null) return null;
+            if(ob == null)
+                return null;
 
             /*
              * If it is already one of our interfaces, extract the script-defined class object from it.
              */
-            if (ob is Delegate[]) {
+            if(ob is Delegate[])
+            {
                 Delegate[] da = (Delegate[])ob;
                 ob = da[0].Target;
             }
@@ -239,21 +253,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
         /**
          * @brief Write the whole thing out to a stream.
          */
-        public void Capture (XMRInstArrays.Sender sendValue)
+        public void Capture(XMRInstArrays.Sender sendValue)
         {
-            sendValue (this.sdtcClass.sdTypeIndex);
-            this.instVars.SendArrays (sendValue);
+            sendValue(this.sdtcClass.sdTypeIndex);
+            this.instVars.SendArrays(sendValue);
         }
 
         /**
          * @brief Read the whole thing in from a stream.
          */
-        public XMRSDTypeClObj () { }
-        public void Restore (XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
+        public XMRSDTypeClObj()
+        {
+        }
+        public void Restore(XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
         {
-            int classindex = (int)recvValue ();
-            Construct (inst, classindex);
-            this.instVars.RecvArrays (recvValue);
+            int classindex = (int)recvValue();
+            Construct(inst, classindex);
+            this.instVars.RecvArrays(recvValue);
         }
     }
 }

+ 240 - 0
OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs

@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Framework.Monitoring;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    public partial class Yengine
+    {
+        private int m_WakeUpOne = 0;
+        public object m_WakeUpLock = new object();
+
+        private Dictionary<int, XMRInstance> m_RunningInstances = new Dictionary<int, XMRInstance>();
+
+        private bool m_SuspendScriptThreadFlag = false;
+        private bool m_WakeUpThis = false;
+        public DateTime m_LastRanAt = DateTime.MinValue;
+        public long m_ScriptExecTime = 0;
+
+        [ThreadStatic]
+        private static int m_ScriptThreadTID;
+
+        public static bool IsScriptThread
+        {
+            get
+            {
+                return m_ScriptThreadTID != 0;
+            }
+        }
+
+        public void StartThreadWorker(int i)
+        {
+            Thread thd;
+            if(i >= 0)
+                thd = Yengine.StartMyThread(RunScriptThread, "YScript" + i.ToString(), ThreadPriority.BelowNormal);
+            else
+                thd = Yengine.StartMyThread(RunScriptThread, "YScript", ThreadPriority.BelowNormal);
+            lock(m_WakeUpLock)
+                m_RunningInstances.Add(thd.ManagedThreadId, null);
+        }
+
+        public void StopThreadWorkers()
+        {
+            lock(m_WakeUpLock)
+            {
+                while(m_RunningInstances.Count != 0)
+                {
+                    Monitor.PulseAll(m_WakeUpLock);
+                    Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
+                }
+            }
+        }
+
+        /**
+         * @brief Something was just added to the Start or Yield queue so
+         *        wake one of the RunScriptThread() instances to run it.
+         */
+        public void WakeUpOne()
+        {
+            lock(m_WakeUpLock)
+            {
+                m_WakeUpOne++;
+                Monitor.Pulse(m_WakeUpLock);
+            }
+        }
+
+        public void SuspendThreads()
+        {
+            lock(m_WakeUpLock)
+            {
+                m_SuspendScriptThreadFlag = true;
+                Monitor.PulseAll(m_WakeUpLock);
+            }
+        }
+
+        public void ResumeThreads()
+        {
+            lock(m_WakeUpLock)
+            {
+                m_SuspendScriptThreadFlag = false;
+                Monitor.PulseAll(m_WakeUpLock);
+            }
+        }
+
+        /**
+         * @brief Thread that runs the scripts.
+         *
+         *        There are NUMSCRIPTHREADWKRS of these.
+         *        Each sits in a loop checking the Start and Yield queues for 
+         *        a script to run and calls the script as a microthread.
+         */
+        private void RunScriptThread()
+        {
+            int tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
+            ThreadStart thunk;
+            XMRInstance inst;
+            bool didevent;
+            m_ScriptThreadTID = tid;
+
+            while(!m_Exiting)
+            {
+                Yengine.UpdateMyThread();
+
+                lock(m_WakeUpLock)
+                {
+                    // Maybe there are some scripts waiting to be migrated in or out.
+                    thunk = null;
+                    if(m_ThunkQueue.Count > 0)
+                        thunk = m_ThunkQueue.Dequeue();
+
+                    // Handle 'xmr resume/suspend' commands.
+                    else if(m_SuspendScriptThreadFlag && !m_Exiting)
+                    {
+                        Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
+                        Yengine.UpdateMyThread();
+                        continue;
+                    }
+                }
+
+                if(thunk != null)
+                {
+                    thunk();
+                    continue;
+                }
+
+                if(m_StartProcessing)
+                {
+                    // If event just queued to any idle scripts
+                    // start them right away.  But only start so
+                    // many so we can make some progress on yield
+                    // queue.
+                    int numStarts;
+                    didevent = false;
+                    for(numStarts = 5; numStarts >= 0; --numStarts)
+                    {
+                        lock(m_StartQueue)
+                            inst = m_StartQueue.RemoveHead();
+
+                        if(inst == null)
+                            break;
+                        if(inst.m_IState != XMRInstState.ONSTARTQ)
+                            throw new Exception("bad state");
+                        RunInstance(inst, tid);
+                        if(m_SuspendScriptThreadFlag || m_Exiting)
+                            continue;
+                        didevent = true;
+                    }
+
+                    // If there is something to run, run it
+                    // then rescan from the beginning in case
+                    // a lot of things have changed meanwhile.
+                    //
+                    // These are considered lower priority than
+                    // m_StartQueue as they have been taking at
+                    // least one quantum of CPU time and event
+                    // handlers are supposed to be quick.
+                    lock(m_YieldQueue)
+                        inst = m_YieldQueue.RemoveHead();
+
+                    if(inst != null)
+                    {
+                        if(inst.m_IState != XMRInstState.ONYIELDQ)
+                            throw new Exception("bad state");
+                        RunInstance(inst, tid);
+                        continue;
+                    }
+
+                    // If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
+                    if(didevent)
+                        continue;
+                }
+
+                // Nothing to do, sleep.
+                lock(m_WakeUpLock)
+                {
+                    if(!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
+                        Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
+
+                    m_WakeUpThis = false;
+                    if((m_WakeUpOne > 0) && (--m_WakeUpOne > 0))
+                        Monitor.Pulse(m_WakeUpLock);
+                }
+            }
+            lock(m_WakeUpLock)
+                m_RunningInstances.Remove(tid);
+
+            Yengine.MyThreadExiting();
+        }
+
+        /**
+         * @brief A script instance was just removed from the Start or Yield Queue.
+         *        So run it for a little bit then stick in whatever queue it should go in.
+         */
+        private void RunInstance(XMRInstance inst, int tid)
+        {
+            m_LastRanAt = DateTime.UtcNow;
+            m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds;
+            inst.m_IState = XMRInstState.RUNNING;
+
+            lock(m_WakeUpLock)
+                m_RunningInstances[tid] = inst;
+
+            XMRInstState newIState = inst.RunOne();
+
+            lock(m_WakeUpLock)
+                m_RunningInstances[tid] = null;
+
+            HandleNewIState(inst, newIState);
+            m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
+        }
+    }
+}

+ 97 - 0
OpenSim/Region/ScriptEngine/YEngine/XMRScriptUThread.cs

@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSimulator Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
+
+namespace OpenSim.Region.ScriptEngine.Yengine
+{
+
+    public partial class XMRInstance
+    {
+        /**
+        * @brief Start script event handler from the beginning.
+        *        Return when either the script event handler completes
+        *        or the script calls Hiber().
+        * @returns null: script did not throw any exception so far
+        *          else: script threw an exception
+        */
+        public Exception StartEx()
+        {
+            // Start script event handler from very beginning.
+            callMode = XMRInstance.CallMode_NORMAL;
+            try
+            {
+                CallSEH();                 // run script event handler
+            }
+            catch(StackHibernateException)
+            {
+                if(callMode != XMRInstance.CallMode_SAVE)
+                    throw new Exception("callMode=" + callMode);
+            }
+            catch(Exception e)
+            {
+                return e;
+            }
+
+            return null;
+        }
+
+        /**
+         * @brief We now want to run some more script code from where it last hibernated
+         *        until it either finishes the script event handler or until the script
+         *        calls Hiber() again.
+         */
+        public Exception ResumeEx()
+        {
+            // Resume script from captured stack.
+            callMode = XMRInstance.CallMode_RESTORE;
+            suspendOnCheckRunTemp = true;
+            try
+            {
+                CallSEH();                 // run script event handler
+            }
+            catch(StackHibernateException)
+            {
+                if(callMode != XMRInstance.CallMode_SAVE)
+                    throw new Exception("callMode=" + callMode);
+            }
+            catch(Exception e)
+            {
+                return e;
+            }
+
+            return null;
+        }
+
+        public class StackHibernateException: Exception, IXMRUncatchable
+        {
+        }
+    }
+}

+ 5 - 6
bin/OpenSim.ini.example

@@ -265,8 +265,8 @@
     ; DefaultScriptEngine = "XEngine"
     ;; ***DANGER***DANGER***
     ;; experimental engine
-    ;; see section [XMREngine} below
-    ; DefaultScriptEngine = "XMREngine"
+    ;; see section [YEngine} below
+    ; DefaultScriptEngine = "YEngine"
     
     ;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080
     ;; Http proxy setting for llHTTPRequest and dynamic texture loading, if
@@ -922,20 +922,19 @@
 [XMREngine]
     ;; experimental engine
     ;; ONLY SUPORTS ONE REGION PER INSTANCE at this point
-    ;; implements microthreading, so fixing problems like llSleep or long events handlers
+    ;; implements non preemptive microthreading, so fixing problems like llSleep or long events handlers
     ;; but those will suffer from timeslicing, so will be slower.
     ;; compiles LSL directly to IL, so only suports LSL scripting (no C# etc) 
     ;; shares the Xengine APIs like LSL, OSSL, etc.
     ;; DANGER, do not use with HG, don't leave regions running alone with it.
-    ;; TPs or crossings to/from Xengine will recompile scripts losing state.
+    ;; TPs or crossings to/from Xengine will full recompile scripts losing state.
     ;; attachment scripts may misbehave, cars will stop on crossings, etc.
     Enabled = false
-    UThreadModel = sys
     ScriptStackSize = 256
     ScriptHeapSize = 256
     UseSourceHashCode = true
     MinTimerInterval = 0.1
-    ;ScriptBasePath="ScriptData"
+    ;ScriptBasePath="ScriptEngines"
 
 [XEngine]
     ;# {Enabled} {} {Enable the XEngine scripting engine?} {true false} true

+ 2 - 2
prebuild.xml

@@ -2418,8 +2418,8 @@
       </Files>
     </Project>
 
-    <!-- XMRengine -->   
-    <Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.XMREngine" path="OpenSim/Region/ScriptEngine/XMREngine" type="Library">
+    <!-- YEngine/core XMRengine -->   
+    <Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.YEngine" path="OpenSim/Region/ScriptEngine/YEngine" type="Library">
       <Configuration name="Debug">
         <Options>
           <OutputPath>../../../../bin/</OutputPath>

Some files were not shown because too many files changed in this diff