コード例 #1
0
ファイル: FunctionNode.cs プロジェクト: zerodowned/UO-Forever
        public Object Execute(TriggerObject trigObject, bool tryReturnObject = false)
        {
            if (trigObject == null)
            {
                throw new UberScriptException("Execute: trigObject reference is null");
            }

            var args = new List <Object> {
                trigObject
            };

            // the args of the function are actually
            // stored in nodes--either function or argument... e.g.
            // EFFECT(14000,25, THIS().x, THIS().y, THIS().z)
            // has 2 argument nodes and 3 function nodes

            // each child of a FunctionNode is an argument represented by a MathTree
            foreach (UberNode child in Children)
            {
                if (!(child is MathTree))
                {
                    throw new UberScriptException(
                              String.Format("Execute: MathTree child expected at line {0}:\n{1}", LineNumber, OriginalString));
                }

                MathTree mathTree = child as MathTree;

                if (!mathTree.IsEmpty())
                {
                    args.Add(mathTree.Calculate(trigObject));
                }
            }

            Object obj;

            try
            {
                // FunctionNode scriptstring contains function name
                obj = UberScriptFunctions.Invoke(ScriptString, args.ToArray());
            }
            catch (Exception x)
            {
                throw new UberScriptException(
                          String.Format("Execute: an exception was thrown during invocation at line {0}:\n{1}", LineNumber, OriginalString),
                          x);
            }

            if (Property == null || tryReturnObject)
            {
                return(obj);
            }

            Type ptype;

            try
            {
                obj = PropertyGetters.GetObject(trigObject, obj, Property, out ptype);

                if (obj == null)
                {
                    return(null);                    // it's ok to be null here
                }
            }
            catch (Exception x)
            {
                throw new UberScriptException(
                          String.Format(
                              "Execute: value could not be set on function '{0}' output object at line {1}:\n{2}",
                              ScriptString,
                              LineNumber,
                              OriginalString),
                          x);
            }

            if (ptype == null)
            {
                throw new UberScriptException(
                          String.Format(
                              "Execute: property '{0}' does not exist on function '{1}' output object at line {2}:\n{3}",
                              Property,
                              ScriptString,
                              LineNumber,
                              OriginalString));
            }

            if (NegateOutput)
            {
                if (obj is sbyte)
                {
                    obj = -(sbyte)obj;
                }
                else if (obj is short)
                {
                    obj = -(short)obj;
                }
                else if (obj is int)
                {
                    obj = -(int)obj;
                }
                else if (obj is long)
                {
                    obj = -(long)obj;
                }
                else
                {
                    throw new UberScriptException(
                              String.Format(
                                  "Execute: output negation failed on function '{0}' output object type '{1}' at line {2}:\n{3}",
                                  ScriptString,
                                  obj.GetType(),
                                  LineNumber,
                                  OriginalString));
                }
            }

            return(obj);
        }
コード例 #2
0
        public static RootNode ParseFileContents(string[] lines, string fileName)
        {
            CurrentFileBeingParsed = fileName;

            // ERROR HANDLING OUTSIDE OF THIS FUNCTION
            var      balanceStack      = new Stack <UberNode>();
            RootNode root              = new RootNode(null, null);
            RootNode currentRoot       = root;       // spawn nodes are root nodes
            UberNode current           = root;
            UberNode prev              = null;
            int      currentLineNumber = 0;
            int      openCurlyBraces   = 0;

            var cleanedStrings = new List <CleanLine>();

            foreach (string line in lines)
            {
                //Console.WriteLine(line);
                currentLineNumber++;

                StringBuilder sb          = new StringBuilder();
                string        cleanedLine = line.Trim();

                if (cleanedLine.StartsWith("//"))
                {
                    continue;
                }

                bool insideQuotation            = false;
                bool justEscapedBackslash       = false;
                bool possibleComment            = false;
                int  forLoopRemainingSemiColons = 0;

                for (int i = 0; i < cleanedLine.Length; i++)
                {
                    if (cleanedLine[i] == '\t')
                    {
                        continue;                         // always remove tabs... not allowed even in strings..
                    }

                    if (cleanedLine[i] == '\\')
                    {
                        if (!insideQuotation)
                        {
                            throw new UberScriptException(
                                      String.Format(
                                          "Parse: unexpected escape token '\\' in '{0}' at line {1}:\n{2}", fileName, currentLineNumber, cleanedLine));
                        }

                        if (!justEscapedBackslash)
                        {
                            if (i > 0 && cleanedLine[i - 1] == '\\')
                            {
                                justEscapedBackslash = true;
                            }
                        }
                        else
                        {
                            justEscapedBackslash = false;
                        }

                        sb.Append('\\');                         // keep the double backslash in there regardless (it is handled in MathTree.ParseOperand)
                        continue;
                    }

                    if (cleanedLine[i] == '"')
                    {
                        if (!(i > 0 && cleanedLine[i - 1] == '\\' && !justEscapedBackslash))
                        {
                            insideQuotation = !insideQuotation;
                        }

                        sb.Append("\"");                         // add \" to the string
                        continue;
                    }

                    justEscapedBackslash = false;                     // make sure to reset this if you have gotten to this point

                    if (insideQuotation)
                    {
                        sb.Append(cleanedLine[i]);
                        continue;
                    }

                    if (cleanedLine[i] == '/')
                    {
                        if (possibleComment)
                        {
                            sb.Remove(sb.Length - 1, 1);                             // remove the previously added / character
                            break;
                        }

                        possibleComment = true;
                        sb.Append('/');
                        continue;
                    }

                    possibleComment = false;

                    if (cleanedLine[i] == ' ' || cleanedLine[i] == '\t')
                    {
                        continue;
                    }

                    // handle lines with multiple delimiters (e.g. orc { name = "Bob"; } )
                    if (cleanedLine[i] == '{' || cleanedLine[i] == '}')
                    {
                        // check if unbalanced
                        if (cleanedLine[i] == '{')
                        {
                            openCurlyBraces++;
                        }
                        else
                        {
                            openCurlyBraces--;
                        }

                        if (openCurlyBraces < 0)
                        {
                            throw new UberScriptException(
                                      String.Format(
                                          "Parse: brace mismatch detected in '{0}' at line {1}:\n{2}", fileName, currentLineNumber, cleanedLine));
                        }

                        // add everything before the { or } (if there is anything)
                        if (i > 0)
                        {
                            cleanedStrings.Add(new CleanLine(currentLineNumber, sb.ToString()));
                        }

                        cleanedStrings.Add(new CleanLine(currentLineNumber, cleanedLine[i].ToString(CultureInfo.InvariantCulture)));

                        // add { or } on separate "line" (it's processed as a line)
                        cleanedLine = cleanedLine.Substring(i + 1);
                        i           = -1;
                        sb.Clear();

                        continue;
                    }

                    if (cleanedLine[i] == ';')
                    {
                        if (cleanedLine.Length == i + 1)
                        {
                            break;
                        }                         // we are at the end of the loop, ignore lines ending in semicolon

                        string stringPreviousToSemiColon = sb.ToString();

                        if (stringPreviousToSemiColon.Contains("for"))
                        {
                            if (stringPreviousToSemiColon.Contains("foreach("))
                            {
                                forLoopRemainingSemiColons += 1;
                            }
                            else if (stringPreviousToSemiColon.Contains("for("))                             // for loop has 2 semicolons
                            {
                                forLoopRemainingSemiColons += 2;
                            }
                        }

                        if (forLoopRemainingSemiColons == 0)
                        {
                            // we have encountered a statement-separating semi-colon!
                            // add everything before the { or } (if there is anything)
                            if (i > 0)
                            {
                                cleanedStrings.Add(new CleanLine(currentLineNumber, sb.ToString()));
                            }

                            cleanedLine = cleanedLine.Substring(i + 1);
                            i           = -1;
                            sb.Clear();

                            continue;
                        }

                        forLoopRemainingSemiColons--;
                    }

                    sb.Append(cleanedLine[i]);
                }

                cleanedLine = sb.ToString();

                if (!String.IsNullOrWhiteSpace(cleanedLine) && !cleanedLine.StartsWith("//"))
                {
                    cleanedStrings.Add(new CleanLine(currentLineNumber, sb.ToString()));
                }
            }

            foreach (CleanLine cleanedString in cleanedStrings)
            {
                // i have to use this CleanLine object to keep track of line numbers
                // in spite of {, }, and ; characters splitting the lines up!
                currentLineNumber = cleanedString.LineNumber;

                string cleanedLine = cleanedString.Value;

                if (cleanedLine == "" || cleanedLine.StartsWith("//"))
                {
                    continue;
                }

                if (cleanedLine == "{")
                {
                    balanceStack.Push(current);

                    if (prev != null)
                    {
                        current = prev;
                    }

                    continue;
                }

                if (cleanedLine == "}")
                {
                    if (balanceStack.Count > 0)
                    {
                        current = balanceStack.Pop();

                        if (current is RootNode)
                        {
                            // likely we have finished procesinto a spawn nodes (ChildRoots)
                            // and therefore need to go back to the spawn node's root
                            // so triggers are correctly assigned to it
                            currentRoot = current.GetRootNode;
                        }

                        continue;
                    }

                    throw new UberScriptException(
                              String.Format(
                                  "Parse: brace mismatch detected in '{0}' at line {1}:\n{2}", fileName, currentLineNumber, cleanedLine));
                }
                // remove ending ";" characters (doesn't matter if you end with ; or not)
                // CANNOT do more than one statement on a line, though.

                // determine which type of node it is
                string lowerCase = cleanedLine.ToLower();

                if (UberScriptTriggers.HasTrigger(lowerCase))
                {
                    prev = new TriggerNode(current, lowerCase);

                    //Console.WriteLine(current + "->" + prev);

                    currentRoot.TriggerNodes.Add(prev as TriggerNode);
                }
                else if (char.IsDigit(cleanedLine[0]))                 // must be a sequence node
                {
                    int stage;

                    if (!Int32.TryParse(cleanedLine, out stage))
                    {
                        throw new UberScriptException(
                                  String.Format(
                                      "Parse: incorrect sequence format, integer expected at line {0}:\n{1}", currentLineNumber, cleanedLine));
                    }

                    prev = new SequenceNode(current, cleanedLine, stage);
                }
                else if (cleanedLine.StartsWith("foreach"))
                {
                    /*
                     * objs.moblist = GETNEARBYMOBS(TRIGMOB(),5)
                     *
                     * foreach(objs.mob ; objs.moblist)
                     * {
                     * }
                     */

                    prev = new ForEachNode(current, cleanedLine, currentLineNumber);
                }
                else if (cleanedLine.StartsWith("for"))
                {
                    /*
                     * for(ints.i = 0; ints.i < TRIGMOB().hits; ints.i = ints.i + 1)
                     * {
                     * }
                     */

                    prev = new ForLoopNode(current, cleanedLine, currentLineNumber);
                }
                else if (cleanedLine.StartsWith("if") || cleanedLine.StartsWith("elif") || cleanedLine.StartsWith("else") ||
                         cleanedLine.StartsWith("elseif"))
                {
                    prev = new ConditionalNode(current, cleanedLine, currentLineNumber);

                    //Console.WriteLine(current + "->" + prev);
                }
                else if (cleanedLine.StartsWith("return"))
                {
                    prev = new ReturnNode(current, cleanedLine);

                    if (cleanedLine == "returnoverride")
                    {
                        ((ReturnNode)prev).Override = true;
                    }
                }
                else
                {
                    switch (cleanedLine)
                    {
                    case "break":
                    {
                        // check whether it has a foreach / for ancestor
                        UberNode testParent           = current;
                        bool     foundForNodeAncestor = false;

                        while (testParent != null)
                        {
                            if (testParent is ForEachNode || testParent is ForLoopNode)
                            {
                                foundForNodeAncestor = true;
                                break;
                            }
                            testParent = testParent.Parent;
                        }

                        if (!foundForNodeAncestor)
                        {
                            throw new UberScriptException(
                                      String.Format("Parse: unexpected 'break' statement at line {0}:\n{1}", currentLineNumber, cleanedLine));
                        }

                        prev = new BreakNode(current, cleanedLine);
                    }
                    break;

                    case "continue":
                    {
                        // check whether it has a foreach / for ancestor
                        UberNode testParent           = current;
                        bool     foundForNodeAncestor = false;

                        while (testParent != null)
                        {
                            if (testParent is ForEachNode || testParent is ForLoopNode)
                            {
                                foundForNodeAncestor = true;
                                break;
                            }

                            testParent = testParent.Parent;
                        }

                        if (!foundForNodeAncestor)
                        {
                            throw new UberScriptException(
                                      String.Format("Parse: unexpected 'continue' statement at line {0}:\n{1}", currentLineNumber, cleanedLine));
                        }

                        prev = new ContinueNode(current, cleanedLine);
                    }
                    break;

                    default:
                    {
                        if (cleanedLine.StartsWith("pause"))
                        {
                            double pauseDuration;

                            if (!Double.TryParse(cleanedLine.Substring(5), out pauseDuration))
                            {
                                pauseDuration = 0;
                            }

                            prev = new PauseNode(current, cleanedLine, pauseDuration);
                        }
                        else if (cleanedLine.StartsWith("function"))
                        {
                            prev = new UserDefinedFunctionNode(current, lowerCase);
                            //Console.WriteLine(current + "->" + prev);
                            root.UserDefinedFunctionNodes.Add(prev as UserDefinedFunctionNode);
                        }

                        /*
                         * else if (cleanedLine.StartsWith("spawngroup"))
                         * {
                         *      prev = new SpawnGroupNode
                         * }
                         * else if (cleanedLine.StartsWith("spawnregion"))
                         * {
                         *
                         * }
                         * else if (cleanedLine.StartsWith("spawnentry"))
                         * {
                         *
                         * }
                         */
                        else
                        {
                            int equalCount = 0;
                            //char beforeChar = '\0';
                            int  numOpenParentheses = 0;
                            bool inQuotes           = false;

                            for (int i = 0; i < cleanedLine.Length; i++)
                            {
                                if (!inQuotes)
                                {
                                    if (cleanedLine[i] == '=' && numOpenParentheses == 0)
                                    {
                                        equalCount++;
                                    }
                                    else
                                    {
                                        switch (cleanedLine[i])
                                        {
                                        case '(':
                                            numOpenParentheses++;
                                            break;

                                        case ')':
                                        {
                                            numOpenParentheses--;

                                            if (numOpenParentheses < 0)
                                            {
                                                throw new UberScriptException(
                                                          String.Format(
                                                              "Parse: parentheses mismatch detected in '{0}' at line {1}:\n{2}",
                                                              fileName,
                                                              currentLineNumber,
                                                              cleanedLine));
                                            }
                                        }
                                        break;
                                        }
                                    }
                                }

                                if (cleanedLine[i] != '"')
                                {
                                    continue;
                                }

                                inQuotes = !inQuotes;                                         // assume that it's not an escaped quotation

                                // determine if it is an escaped quotation (and that there aren't escaped backslashes preceding it)
                                for (int ix = i - 1; ix >= 0 && cleanedLine[ix] == '\\'; ix--)
                                {
                                    inQuotes = !inQuotes;                                             // for each backslash behind, unescape or escape accordingly
                                }
                            }

                            if (equalCount == 1)                                     // it's a statement node
                            {
                                prev = new StatementNode(current, cleanedLine, currentLineNumber);
                                //Console.WriteLine(current + "->" + prev);

                                if (((StatementNode)prev).ContainsSpawnNode)
                                {
                                    // global_objs.test = orc
                                    // {
                                    //      name = goober
                                    // }
                                    prev.LineNumber = currentLineNumber;                                    // we "continue" here so we set this later
                                    current.Children.Add(prev);                                             // we "continue" here so we don't add it later
                                    //Console.WriteLine(current + "->" + prev + "... adding spawn node to statement node!");

                                    prev = prev.Children[1];                                             // should contain a spawn node
                                    currentRoot.ChildRoots.Add(prev as RootNode);
                                    currentRoot = prev as RootNode;                                      // spawn node become the new root node
                                    continue;
                                }
                            }
                            else if (UberScriptFunctions.IsFunctionString(cleanedLine))
                            {
                                prev = new FunctionNode(current, cleanedLine, currentLineNumber);
                                //Console.WriteLine(current + "->" + prev);
                            }
                            else if (UserDefinedFunctionNode.GetUserDefinedFunctionString(cleanedLine, root) != null)
                            {
                                prev = new UserDefinedFunctionExectueNode(current, cleanedLine, currentLineNumber);

                                ((UserDefinedFunctionExectueNode)prev).UserDefinedFunction =
                                    UserDefinedFunctionNode.GetUserDefinedFunctionString(cleanedLine, root);
                            }
                            else
                            {
                                // the string might have commas (indicating a spawn type with a constructor accepting arguments
                                // such as "static,100"
                                int commaIndex = cleanedLine.IndexOf(',');

                                Type spawnType =
                                    ScriptCompiler.FindTypeByName(commaIndex > 0 ? cleanedLine.Substring(0, commaIndex) : cleanedLine);

                                if (spawnType != null && typeof(Mobile).IsAssignableFrom(spawnType) || typeof(Item).IsAssignableFrom(spawnType))
                                {
                                    prev = new RootNode(current, cleanedLine);
                                    // keep a list of child root nodes so that spawned creatures that have triggers
                                    // specific to them can correctly point to the right place in the script e.g.
                                    // troll
                                    // {
                                    //      onDeath
                                    //      {
                                    //          orc
                                    //          {
                                    //              onDeath
                                    //              {
                                    //                  ...
                                    //              }
                                    //          }
                                    //      }
                                    // }
                                    // --> trigger nodes are only added to their closest root node
                                    currentRoot.ChildRoots.Add(prev as RootNode);
                                    //Console.WriteLine(current + "->" + prev);
                                    currentRoot = prev as RootNode;                                             // spawn node become the new root node
                                }
                                else
                                {
                                    throw new UberScriptException(
                                              String.Format("Parse: could not parse node at line {0}:\n{1}", currentLineNumber, cleanedLine));
                                }
                            }
                        }
                    }
                    break;
                    }
                }

                current.Children.Add(prev);
                prev.LineNumber = currentLineNumber;                 // used for debugging purposes
            }

            if (balanceStack.Count > 0)
            {
                throw new UberScriptException(
                          String.Format("Parse: brace mismatch detected in '{0}' at line {1}", fileName, currentLineNumber));
            }

            return(root);
        }
コード例 #3
0
        // returns the added operand node
        public static MathNode ParseOperand(string input)
        {
            if (input == null)
            {
                throw new UberScriptException("AddOperand input was null!");
            }
            if (input == "")
            {
                throw new UberScriptException("AddOperand input was an empty string!");
            }
            Object operand = input;
            OpType opType  = OpType.Unassigned;

            try
            {
                int numCommas = 0;
                for (int i = 0; i < input.Length; i++)
                {
                    if (input[i] == ',')
                    {
                        numCommas++;
                    }
                }
                if (input.StartsWith("0x"))
                {
                    try
                    {
                        if (isNegative) // might fail here
                        {
                            operand = Convert.ToInt32(input.Substring(2), 16);
                            opType  = OpType.Int;
                        }
                        else
                        {
                            operand = Convert.ToUInt64(input.Substring(2), 16);
                            // try to use int if at all possible
                            if ((UInt64)operand < 2147483647) // 2^31 - 1
                            {
                                operand = Convert.ToInt32(input.Substring(2), 16);
                                opType  = OpType.Int;
                            }
                            else
                            {
                                opType = OpType.UInt64;
                            }
                        }
                    }
                    catch // (InvalidCastException e)
                    {
                        // must be a string
                        operand = input;
                        opType  = OpType.String;
                    }
                }
                else if (char.IsNumber(input[0]) || input[0] == '.')
                {
                    double doubleVal;
                    bool   result = double.TryParse(input, out doubleVal);
                    if (result == false)
                    {
                        operand = input; // must be something like 016hello, so just treat it as a string
                        opType  = OpType.String;
                    }
                    else
                    {
                        if (isNegative)
                        {
                            doubleVal = -doubleVal; isNegative = false;
                        }
                        if (!input.Contains('.') && doubleVal % 1 < 0.0009765625) // 2^-10
                        {
                            // close enough to an integer value
                            operand = (int)doubleVal;
                            opType  = OpType.Int;
                        }
                        else
                        {
                            operand = doubleVal;
                            opType  = OpType.Double;
                        }
                    }
                }
                else if (input == "null")
                {
                    opType  = OpType.Null;
                    operand = null;
                }
                else if (input.StartsWith("\""))
                {
                    // inside a quotation--> parse out the innards and set it to a string
                    if (!input.EndsWith("\"") || input.Length == 1)
                    {
                        throw new UberScriptException("ParseOperand input started with \" but did not end with \"... it must be balanced!");
                    }
                    input = input.Substring(1, input.Length - 2); // remove the front and back ""
                    bool justEscapedBackslash = false;
                    for (int ix = 0; ix < input.Length; ix++)
                    {
                        if (ix > 0 && input[ix - 1] == '\\')
                        {
                            // not super efficient, but oh well, it's only run once
                            if (!justEscapedBackslash)
                            {
                                if (input[ix] == '"')
                                {
                                    input = input.Substring(0, ix - 1) + input.Substring(ix); // remove the \, keep the "
                                    ix--;
                                }
                                else if (input[ix] == 't')
                                {
                                    input = input.Substring(0, ix - 1) + "\t" + input.Substring(ix + 1); // remove the \ and add a tab
                                    ix--;
                                }
                                else if (input[ix] == 'n')
                                {
                                    input = input.Substring(0, ix - 1) + "\n" + input.Substring(ix + 1); // remove the \ and add a new line
                                    ix--;
                                }
                                else if (input[ix] == 'r')
                                {
                                    input = input.Substring(0, ix - 1) + "\r" + input.Substring(ix + 1); // remove the \ and add a carriage return
                                    ix--;
                                }
                                else if (input[ix] == '\\')
                                {
                                    input = input.Substring(0, ix - 1) + input.Substring(ix); // keep only one of the \ characters
                                    justEscapedBackslash = true;
                                    continue;
                                }
                            }
                            // otherwise ignore it
                        }
                        justEscapedBackslash = false;
                    }
                    operand = input;
                    opType  = OpType.String;
                }
                else if (UberScriptFunctions.IsFunctionString(input))
                {
                    MathNode latestRootNode = currentRoot;       // currentRoot is replaced when FunctionNode adds a mathtree for each arg
                    currentRoot = null;
                    operand     = new FunctionNode(null, input); // can't add LineNumber here :(
                    if (isNegative)
                    {
                        ((FunctionNode)operand).NegateOutput = true; isNegative = false;
                    }
                    opType      = OpType.Func;
                    currentRoot = latestRootNode;
                }
                // NOTE: While the performance is not as good (perhaps), I'm going to rely on parsing list accession (e.g. objs.mobs[objs.mobs.count - 1])
                // on the fly (as is done in the PropertySetters and PropertyGetters functions) rather than pre-parsing it.

                /*
                 * else if (UberScriptFunctions.IsArrayAccessor(input))
                 * {
                 *  MathNode latestRootNode = currentRoot; // currentRoot is replaced when FunctionNode adds a mathtree for each arg
                 *  currentRoot = null;
                 *  operand = new ListAccessNode(null, input); // can't add LineNumber here :(
                 *  if (isNegative) { ((ListAccessNode)operand).NegateOutput = true; isNegative = false; }
                 *  opType = OpType.ListAccess;
                 *  currentRoot = latestRootNode;
                 * }*/

                /* // I'm not going to handle literal points e.g. (1,2,3)... use the LOC function instead (so you can do math in it)
                 * else if (numCommas > 1) // it must be a location if it is not a function and has 2 commas in it
                 * {
                 *  operand = "(" + input + ")";
                 *  opType = OpType.String;
                 * }*/
                else
                {
                    operand = input;
                    opType  = OpType.String;
                }


                MathNode newOperandNode = new MathNode(null, null, opType, TreePriority.Operand, operand); // assigned into tree in constructor!
                return(newOperandNode);
            }
            catch (Exception e)
            {
                Console.WriteLine("AddOperand error: " + e.Message + "\n" + e.StackTrace);
                throw new UberScriptException("AddOperand error for " + input, e);
            }
        }
コード例 #4
0
        public Object Execute(TriggerObject trigObject, bool tryReturnObject = false)
        {
            List <Object> args = new List <Object>();

            args.Add(trigObject); // every function takes this as a parameter
            // the args of the function are actually
            // stored in nodes--either function or argument... e.g.
            // EFFECT(14000,25, THIS().x, THIS().y, THIS().z)
            // has 2 argument nodes and 3 function nodes

            // each child of a ListAccessNode is an argument represented by a MathTree
            foreach (UberNode child in Children)
            {
                if (child is MathTree)
                {
                    MathTree mathTree = child as MathTree;
                    if (!mathTree.IsEmpty())
                    {
                        args.Add(mathTree.Calculate(trigObject));
                    }

                    //Execute(trigObject, tryReturnObject = false));
                }
                else
                {
                    throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nListAccessNode had children other than MathTree... something is broken!");
                }
            }
            object[] reflectionArgs = new object[args.Count];
            int      count          = 0;

            foreach (Object arg in args)
            {
                reflectionArgs[count] = arg;
                count++;
            }
            Object outputObject;

            /*
             * if (ScriptString == "THIS") { outputObject = trigObject.This; }
             * else if (ScriptString == "TRIGMOB") { outputObject = trigObject.TrigMob; }
             * else if (ScriptString == "GIVENTOTHIS") { outputObject = trigObject.DroppedOnThis; }
             * else if (ScriptString == "GIVENBYTHIS") { outputObject = trigObject.DroppedOnThis; }
             * else if (ScriptString == "TARGETTEDBY") { outputObject = trigObject.TargettedBy; }
             * else if (ScriptString == "TARGETTED") { outputObject = trigObject.Targetted; }
             * else if (ScriptString == "DAMAGE") { outputObject = trigObject.Damage; }
             * else*/
            try
            {
                outputObject = UberScriptFunctions.Invoke(this.ScriptString, reflectionArgs); // ListAccessNode scriptstring contains function name
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nError invoking function:", e);
            }

            if (Property == null || tryReturnObject)
            {
                return(outputObject);
            }
            Type ptype;

            try
            {
                outputObject = PropertyGetters.GetObject(trigObject, outputObject, Property, out ptype);
                if (outputObject == null)
                {
                    return(null);                      // it's ok to be null here
                }
            }
            catch (Exception e)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nError setting value:", e);
            }
            if (ptype == null)
            {
                throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nListAccessNode function " + ScriptString + " output object did not have property: " + Property);
            }
            if (NegateOutput)
            {
                Type outputType = outputObject.GetType();
                if (outputType == typeof(SByte))
                {
                    outputObject = -((SByte)outputObject);
                }
                else if (outputType == typeof(Int16))
                {
                    outputObject = -((Int16)outputObject);
                }
                else if (outputType == typeof(Int32))
                {
                    outputObject = -((Int32)outputObject);
                }
                else if (outputType == typeof(Int64))
                {
                    outputObject = -((Int64)outputObject);
                }
                else
                {
                    throw new UberScriptException("Line " + LineNumber + ": " + OriginalString + "\nCould not negate output of " + this.ScriptString + " output object of type: " + outputType);
                }
            }
            return(outputObject);
        }
コード例 #5
0
        public void ParseMath(string input)
        {
            int currentIndex = 0;
            Stack <MathNode> prevRootNodes = new Stack <MathNode>();

            currentRoot = null;
            isNegative  = false;
            int    numOpenParensInFunctionCallString = 0; // should be 0 if we are not in a function call, never less than 0
            int    totalOpenParens = 0;                   // should never be less than 0
            string operatorsSupportingUnaryMinus = "+-*/^%(<=>";
            bool   insideQuotation        = false;
            int    totalOpenSquareBracket = 0;

            if (input == "")
            {
                currentRoot = new MathNode(null, null, OpType.String, TreePriority.Operand, String.Empty);
                Children.Add(currentRoot);
                return;
            }

            // if it is an array, there can be nothing more in the math tree
            if (input.StartsWith("[") && input.EndsWith("]"))
            {
                MathNode      arrayNode = new MathNode(null, input, OpType.Array, TreePriority.Infinite);
                string        inArray   = input.Substring(1, input.Length - 2);
                List <string> elements  = new List <string>();
                for (int i = 0; i < inArray.Length; i++)
                {
                    char c = inArray[i];
                    if (insideQuotation && c != '"')
                    {
                        continue;
                    }

                    if (c == '(')
                    {
                        totalOpenParens += 1;
                    }
                    else if (c == ')')
                    {
                        totalOpenParens -= 1;
                        if (totalOpenParens < 0)
                        {
                            throw new Exception("Unbalanced () characters in math string!");
                        }
                    }
                    else if (c == '[')
                    {
                        totalOpenSquareBracket += 1;
                    }
                    else if (c == ']')
                    {
                        totalOpenSquareBracket -= 1;
                        if (totalOpenSquareBracket < 0)
                        {
                            throw new Exception("Unbalanced [] characters in math string!");
                        }
                    }
                    else
                    {
                        if (totalOpenParens > 0 || totalOpenSquareBracket > 0)
                        {
                            continue;
                        }

                        if (c == '"')
                        {
                            /* I'm not sure why I thought I need to do this here; it's taken care of in the MathTree parsing
                             * if (i > 0 && inArray[i-1] == '\\')
                             * {
                             *  // not super efficient, but oh well, it's only run once
                             *  inArray = inArray.Substring(0, i - 1) + inArray.Substring(i); // remove the \, keep the "
                             *  i--;
                             * }
                             * else
                             * {
                             *  inArray = inArray.Substring(0, i) + inArray.Substring(i+1); // remove the "
                             *  i--;
                             */
                            insideQuotation = !insideQuotation;
                            //}
                        }
                        else if (c == ',')
                        {
                            elements.Add(inArray.Substring(0, i));
                            inArray = inArray.Substring(i + 1);
                            i       = -1;
                        }
                    }
                }
                if (inArray.Length > 0)
                {
                    elements.Add(inArray);
                }                                                  // add final element

                ArrayList arrayList = new ArrayList(elements.Count + 10);

                foreach (string element in elements)
                {
                    arrayList.Add(new MathTree(null, element));
                }
                arrayNode.Value = arrayList;
                Children.Add(arrayNode);
                return;
            }

            bool justEscapedBackslash = false;

            for (int i = 0; i < input.Length; i++)
            {
                char   c = input[i];
                string arg;

                if (insideQuotation && c != '"')
                {
                    if (c == '\\')
                    {
                        if (i > 0 && input[i - 1] == '\\' && !justEscapedBackslash)
                        {
                            justEscapedBackslash = true;
                            continue;
                        }
                    }
                    justEscapedBackslash = false;
                    continue;
                }

                if (c == '"')
                {
                    if (i > 0 && input[i - 1] == '\\' && !justEscapedBackslash)
                    {
                        continue; // it's an escaped \" character
                    }
                    else
                    {
                        // --> I'm putting this in the ParseOperand area
                        //input = input.Substring(0, i) + input.Substring(i+1); // remove the "
                        //i--;
                        insideQuotation = !insideQuotation;
                    }
                }


                if (totalOpenSquareBracket > 0 && c != ']')
                {
                    if (c == '[')
                    {
                        totalOpenSquareBracket++;
                    }
                    continue;
                }
                else if (c == '[')
                {
                    totalOpenSquareBracket++;
                }
                else if (c == ']')
                {
                    if (totalOpenSquareBracket > 0)
                    {
                        totalOpenSquareBracket--;
                    }
                    else
                    {
                        throw new Exception("Unbalanced [] characters in list accessing string!");
                    }
                }

                if (numOpenParensInFunctionCallString > 0 && c != '(' && c != ')')
                {
                    // don't do anything in the middle of a function string
                    continue;
                }

                if (c == '|')
                {
                    if (input[i + 1] == '|')
                    {
                        AddOperationNode(ref input, OpType.Or, TreePriority.Or, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        throw new UberScriptException("Single | encountered!  Use || for logical 'or' operator. Note that the bitwise '|' operator currently not supported!");
                        //AddOperationNode(ref input, OpType.BitOr, TreePriority.BitAnd, i, ref currentIndex);
                    }
                }
                else if (c == '&')
                {
                    if (input[i + 1] == '&')
                    {
                        AddOperationNode(ref input, OpType.And, TreePriority.And, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        throw new UberScriptException("Single & encountered!  Use && for logical 'and' operator. Note that the bitwise '&' operator currently not supported!");
                        //AddOperationNode(ref input, OpType.BitAnd, TreePriority.BitAnd, i, ref currentIndex);
                    }
                }
                else if (c == '>')
                {
                    if (input[i + 1] == '=')
                    {
                        AddOperationNode(ref input, OpType.GThanOrEqualTo, TreePriority.Comparison, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        AddOperationNode(ref input, OpType.GThan, TreePriority.Comparison, i, ref currentIndex);
                    }
                }
                else if (c == '<')
                {
                    if (input[i + 1] == '=')
                    {
                        AddOperationNode(ref input, OpType.LThanOrEqualTo, TreePriority.Comparison, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        AddOperationNode(ref input, OpType.LThan, TreePriority.Comparison, i, ref currentIndex);
                    }
                }
                else if (c == '!')
                {
                    if (input[i + 1] == '=')
                    {
                        AddOperationNode(ref input, OpType.NotEqualTo, TreePriority.Comparison, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        throw new UberScriptException("Cannot have a single = sign!");
                    }
                }
                else if (c == '=')
                {
                    if (input[i + 1] == '=')
                    {
                        AddOperationNode(ref input, OpType.EqualTo, TreePriority.Comparison, i, ref currentIndex);
                        i++;
                    }
                    else
                    {
                        throw new UberScriptException("Cannot have a single = sign!");
                    }
                }
                else if (c == '+')
                {
                    AddOperationNode(ref input, OpType.Add, TreePriority.AddSub, i, ref currentIndex);
                }
                else if (c == '-')
                {
                    // i == 0 means a statment is STARTING with -, e.g. -6
                    // otherwise there is something like this ...+-6 or ...*-6, etc
                    if (i == 0 || (i > 0 && (operatorsSupportingUnaryMinus.Contains(input[i - 1]))))
                    {
                        isNegative   = !isNegative;
                        currentIndex = i + 1;
                    }
                    else
                    {
                        AddOperationNode(ref input, OpType.Sub, TreePriority.AddSub, i, ref currentIndex);
                    }
                }
                else if (c == '*')
                {
                    AddOperationNode(ref input, OpType.Mul, TreePriority.MultDiv, i, ref currentIndex);
                }
                else if (c == '/')
                {
                    AddOperationNode(ref input, OpType.Div, TreePriority.MultDiv, i, ref currentIndex);
                }
                else if (c == '^')
                {
                    AddOperationNode(ref input, OpType.Pow, TreePriority.Power, i, ref currentIndex);
                }
                else if (c == '%')
                {
                    AddOperationNode(ref input, OpType.Mod, TreePriority.MultDiv, i, ref currentIndex);
                }
                else if (c == '(')
                {
                    totalOpenParens++;
                    // must check if it is a function call
                    if (numOpenParensInFunctionCallString == 0)
                    {
                        if (UberScriptFunctions.IsFunctionString(input.Substring(currentIndex, i - currentIndex).Trim()))
                        {
                            numOpenParensInFunctionCallString++;
                            continue;
                        }
                        // it's not a function call, it's an order of operations open parenthesis
                        prevRootNodes.Push(currentRoot);
                        MathNode openParenPlaceholder = new MathNode(null, null, OpType.OpenParenthesis, TreePriority.Operand);
                        InsertIntoTree(currentRoot, openParenPlaceholder);
                        currentRoot  = openParenPlaceholder;
                        currentIndex = i + 1;
                    }
                    else
                    {
                        numOpenParensInFunctionCallString++; // keep incrementing it
                    }
                }
                else if (c == ')')
                {
                    totalOpenParens--;
                    if (totalOpenParens < 0)
                    {
                        throw new Exception("Unbalanced () characters in math string!");
                    }
                    if (numOpenParensInFunctionCallString > 0)
                    {
                        numOpenParensInFunctionCallString--;
                        if (numOpenParensInFunctionCallString < 0)
                        {
                            throw new Exception("Unbalanced () characters in function call string!");
                        }
                    }
                    else
                    {
                        // should be an operand or ) right before this )
                        arg = input.Substring(currentIndex, i - currentIndex).Trim();
                        if (arg == "" && !(i > 0 && input[i - 1] == ')'))
                        {
                            throw new UberScriptException("Math parse error: no operand before operator for input=" + input);
                        }
                        if (currentRoot == null)
                        {
                            throw new UberScriptException("Math parse error: can't have ) without a ( currentRoot! input=" + input);
                        }                                                                                                                                     // should be impossible

                        if (arg != "")
                        {
                            InsertIntoTree(currentRoot, ParseOperand(arg));
                        }
                        currentIndex = i + 1;
                        MathNode prevRootNode = prevRootNodes.Pop();
                        currentRoot.Priority = TreePriority.Infinite;
                        if (prevRootNode != null)
                        {
                            currentRoot = prevRootNode; // return up a level
                        }
                        // else the first character in the input was (, so there was no root node initially, so keep the currentNode
                    }
                }
            }

            if (insideQuotation)
            {
                throw new UberScriptException("Unbalanced \" characters! You must terminate strings with \"");
            }
            ;
            if (totalOpenParens > 0)
            {
                throw new UberScriptException("Did not have matching ()!");
            }
            if (totalOpenSquareBracket > 0)
            {
                throw new UberScriptException("Did not have matching []!");
            }

            if (currentIndex < input.Length)
            {
                if (currentRoot == null)
                {
                    currentRoot = ParseOperand(input.Substring(currentIndex, input.Length - currentIndex));
                }
                else
                {
                    InsertIntoTree(currentRoot, ParseOperand(input.Substring(currentIndex, input.Length - currentIndex)));
                }
            }
            Children.Add(currentRoot);
        }