Beispiel #1
0
        public Object Evaluate(
            Context context,
            Object what,
            bool ignoreStar = false,
            bool discardResults = false)
        {
            if (context.evaluationState != EvaluationState.Normal)
                throw new ScriptError("Invalid Context", null);
            if (context.callDepth >= context.maximumCallDepth)
            {
                context.RaiseNewError("Overflow.", null);
                return null;
            }

            context.callDepth += 1; //All exit points must decrement depth.

            if (what is String)
            {
                var r = EvaluateString(context, what as String, "", discardResults);
                context.callDepth -= 1;
                return r;
            }
            else if (!(what is ScriptObject))
            {
                context.callDepth -= 1;
                return what;
            }

            var node = what as ScriptObject;
            context.currentNode = node;

            if (context.limitExecutionTime && (DateTime.Now - context.executionStart > context.allowedExecutionTime))
            {
                context.RaiseNewError("Timeout.", node);
                context.callDepth -= 1;
                return null;
            }

            if (node.gsp("@prefix") == "*" && !ignoreStar) //Object is a quoted node
            {
                context.callDepth -= 1;
                return node;
            }

            var type = node.gsp("@type");
            if (String.IsNullOrEmpty(type))
            {
                context.callDepth -= 1;
                return node;
            } //Object is not evaluatable code.

            object result = null;

            if (type == "string")
            {
                result = node["@token"];
            }
            else if (type == "stringexpression")
            {
                if (discardResults) //Don't bother assembling the string expression.
                {
                    foreach (var piece in node._children)
                    {
                        if ((piece as ScriptObject).gsp("@type") == "string")
                            continue;
                        else
                        {
                            Evaluate(context, piece);
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                context.callDepth -= 1;
                                return null;
                            }
                        }
                    }
                    result = null;
                }
                else
                {
                    if (node._children.Count == 1) //If there's only a single item, the result is that item.
                    {
                        result = Evaluate(context, node._child(0));
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1;
                            return null;
                        }
                    }
                    else
                    {
                        var resultString = String.Empty;
                        foreach (var piece in node._children)
                        {
                            resultString += ScriptObject.AsString(Evaluate(context, piece));
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                context.callDepth -= 1;
                                return null;
                            }
                        }
                        result = resultString;
                    }
                }
            }
            else if (type == "token")
            {
                result = LookupToken(context, node.gsp("@token"));
                if (context.evaluationState != EvaluationState.Normal)
                {
                    context.callDepth -= 1;
                    return null;
                }
            }
            else if (type == "memberaccess")
            {
                var lhs = Evaluate(context, node._child(0));
                if (context.evaluationState != EvaluationState.Normal)
                { context.callDepth -= 1; return null; }
                String rhs = "";

                if ((node._child(1) as ScriptObject).gsp("@type") == "token")
                    rhs = (node._child(1) as ScriptObject).gsp("@token");
                else
                    rhs = ScriptObject.AsString(Evaluate(context, node._child(1), false));
                if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; }

                if (lhs == null) result = null;
                else if (lhs is ScriptObject)
                {
                    result = (lhs as ScriptObject).GetProperty(ScriptObject.AsString(rhs));
                    if (node.gsp("@token") == ":")
                    {
                        context.Scope.PushVariable("this", lhs);
                        result = Evaluate(context, result, true, false);
                        context.Scope.PopVariable("this");
                        if (context.evaluationState != EvaluationState.Normal)
                        { context.callDepth -= 1; return null; }
                    }
                }
                else
                {
                    var field = lhs.GetType().GetField(ScriptObject.AsString(rhs));
                    if (field != null)
                        result = field.GetValue(lhs);
                    else
                    {
                        var prop = lhs.GetType().GetProperty(ScriptObject.AsString(rhs));
                        if (prop != null)
                            result = prop.GetValue(lhs, null);
                        else
                        {
                            var members = lhs.GetType().FindMembers(System.Reflection.MemberTypes.Method,
                                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance,
                                new System.Reflection.MemberFilter((minfo, obj) => { return minfo.Name == obj.ToString(); }),
                                ScriptObject.AsString(rhs));
                            if (members.Length != 0)
                            {
                                result = new GenericScriptObject(
                                    "@lazy-reflection", ScriptObject.AsString(rhs),
                                    "@source-object", lhs,
                                    "@source-type", lhs.GetType());
                            }
                            else
                                result = null;
                        }
                    }
                }
            }
            else if (type == "node")
            {
                if (!ignoreStar && node.gsp("@prefix") == "*")
                {
                    result = node;
                }
                else
                {

                    bool eval = node.gsp("@prefix") != "^";

                    var arguments = new ScriptList();

                    foreach (var child in node._children)
                    {
                        evaluateNodeChild(eval, child, arguments, context);
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1;
                            return null;
                        }
                    }

                    if (node.gsp("@prefix") == "^") result = arguments;
                    else
                    {
                        if (arguments.Count > 0 && Function.IsFunction(arguments[0] as ScriptObject))
                        {

                            result = Function.Invoke((arguments[0] as ScriptObject), this, context,
                                new ScriptList(arguments.GetRange(1, arguments.Count - 1)));
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                if (context.evaluationState == EvaluationState.UnwindingError)
                                    context.PushStackTrace((arguments[0] as ScriptObject).gsp("@name"));
                                context.callDepth -= 1;
                                return null;
                            }

                        }
                        else if (arguments.Count > 0 &&
                            arguments[0] is ScriptObject &&
                            (arguments[0] as ScriptObject).GetProperty("@lazy-reflection") != null)
                        {
                            var sObj = arguments[0] as ScriptObject;
                            var argumentTypes = arguments.GetRange(1, arguments.Count - 1).Select(
                                (obj) => obj.GetType()).ToArray();
                            var sourceObject = sObj.GetProperty("@source-object");
                            var method = (sObj.GetProperty("@source-type") as System.Type)
                                .GetMethod(sObj.gsp("@lazy-reflection"), argumentTypes);
                            if (method == null)
                                throw new ScriptError("Could not find overload for " +
                                    sObj.gsp("@lazy-reflection") + " that takes argument types " +
                                    String.Join(", ", argumentTypes.Select((t) => t.Name)) + " on type " +
                                    sObj.GetProperty("@source-type").ToString(), what as ScriptObject);
                            result = method.Invoke(sourceObject, arguments.GetRange(1, arguments.Count - 1).ToArray());
                        }
                        else if (arguments.Count > 0)
                            result = arguments[0];
                        else
                            result = null;
                    }
                }
            }
            else if (type == "root")
            {
                var results = new ScriptList();
                foreach (var child in node._children)
                {
                    results.Add(Evaluate(context, child, false, false));
                    if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1;
                            return null;
                        }
                    }
                return results;
            }
            else if (type == "number")
            {
                try
                {
                    if (node.gsp("@token").Contains('.')) result = Convert.ToSingle(node.gsp("@token"));
                    else result = Convert.ToInt32(node.gsp("@token"));
                }
                catch (Exception e)
                {
                    context.RaiseNewError("Number format error.", node);
                    { context.callDepth -= 1; return null; }
                }
            }
            else if (type == "char")
            {
                context.callDepth -= 1;
                return node.gsp("@token")[0];
            }
            else
            {
                context.RaiseNewError("Internal evaluator error.", node);
                { context.callDepth -= 1; return null; }
            }

            if (node.gsp("@prefix") == ":" && !ignoreStar)
                result = Evaluate(context, result);
            if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; };
            if (node.gsp("@prefix") == ".") result = LookupToken(context, ScriptObject.AsString(result));
            context.callDepth -= 1;
            return result;
        }
Beispiel #2
0
        public Object Evaluate(
            Context context,
            Object what,
            bool ignoreStar     = false,
            bool discardResults = false)
        {
            if (context.evaluationState != EvaluationState.Normal)
            {
                throw new ScriptError("Invalid Context", null);
            }
            if (context.callDepth >= context.maximumCallDepth)
            {
                context.RaiseNewError("Overflow.", null);
                return(null);
            }

            context.callDepth += 1; //All exit points must decrement depth.

            if (what is String)
            {
                var r = EvaluateString(context, what as String, "", discardResults);
                context.callDepth -= 1;
                return(r);
            }
            else if (!(what is ScriptObject))
            {
                context.callDepth -= 1;
                return(what);
            }

            var node = what as ScriptObject;

            context.currentNode = node;

            if (context.limitExecutionTime && (DateTime.Now - context.executionStart > context.allowedExecutionTime))
            {
                context.RaiseNewError("Timeout.", node);
                context.callDepth -= 1;
                return(null);
            }

            if (node.gsp("@prefix") == "*" && !ignoreStar) //Object is a quoted node
            {
                context.callDepth -= 1;
                return(node);
            }

            var type = node.gsp("@type");

            if (String.IsNullOrEmpty(type))
            {
                context.callDepth -= 1;
                return(node);
            } //Object is not evaluatable code.

            object result = null;

            if (type == "string")
            {
                result = node["@token"];
            }
            else if (type == "stringexpression")
            {
                if (discardResults) //Don't bother assembling the string expression.
                {
                    foreach (var piece in node._children)
                    {
                        if ((piece as ScriptObject).gsp("@type") == "string")
                        {
                            continue;
                        }
                        else
                        {
                            Evaluate(context, piece);
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                context.callDepth -= 1;
                                return(null);
                            }
                        }
                    }
                    result = null;
                }
                else
                {
                    if (node._children.Count == 1) //If there's only a single item, the result is that item.
                    {
                        result = Evaluate(context, node._child(0));
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1;
                            return(null);
                        }
                    }
                    else
                    {
                        var resultString = String.Empty;
                        foreach (var piece in node._children)
                        {
                            resultString += ScriptObject.AsString(Evaluate(context, piece));
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                context.callDepth -= 1;
                                return(null);
                            }
                        }
                        result = resultString;
                    }
                }
            }
            else if (type == "token")
            {
                result = LookupToken(context, node.gsp("@token"));
                if (context.evaluationState != EvaluationState.Normal)
                {
                    context.callDepth -= 1;
                    return(null);
                }
            }
            else if (type == "memberaccess")
            {
                var lhs = Evaluate(context, node._child(0));
                if (context.evaluationState != EvaluationState.Normal)
                {
                    context.callDepth -= 1; return(null);
                }
                String rhs = "";

                if ((node._child(1) as ScriptObject).gsp("@type") == "token")
                {
                    rhs = (node._child(1) as ScriptObject).gsp("@token");
                }
                else
                {
                    rhs = ScriptObject.AsString(Evaluate(context, node._child(1), false));
                }
                if (context.evaluationState != EvaluationState.Normal)
                {
                    context.callDepth -= 1; return(null);
                }

                if (lhs == null)
                {
                    result = null;
                }
                else if (lhs is ScriptObject)
                {
                    result = (lhs as ScriptObject).GetProperty(ScriptObject.AsString(rhs));
                    if (node.gsp("@token") == ":")
                    {
                        context.Scope.PushVariable("this", lhs);
                        result = Evaluate(context, result, true, false);
                        context.Scope.PopVariable("this");
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1; return(null);
                        }
                    }
                }
                else
                {
                    var field = lhs.GetType().GetField(ScriptObject.AsString(rhs));
                    if (field != null)
                    {
                        result = field.GetValue(lhs);
                    }
                    else
                    {
                        var prop = lhs.GetType().GetProperty(ScriptObject.AsString(rhs));
                        if (prop != null)
                        {
                            result = prop.GetValue(lhs, null);
                        }
                        else
                        {
                            var members = lhs.GetType().FindMembers(System.Reflection.MemberTypes.Method,
                                                                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance,
                                                                    new System.Reflection.MemberFilter((minfo, obj) => { return(minfo.Name == obj.ToString()); }),
                                                                    ScriptObject.AsString(rhs));
                            if (members.Length != 0)
                            {
                                result = new GenericScriptObject(
                                    "@lazy-reflection", ScriptObject.AsString(rhs),
                                    "@source-object", lhs,
                                    "@source-type", lhs.GetType());
                            }
                            else
                            {
                                result = null;
                            }
                        }
                    }
                }
            }
            else if (type == "node")
            {
                if (!ignoreStar && node.gsp("@prefix") == "*")
                {
                    result = node;
                }
                else
                {
                    bool eval = node.gsp("@prefix") != "^";

                    var arguments = new ScriptList();

                    foreach (var child in node._children)
                    {
                        evaluateNodeChild(eval, child, arguments, context);
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            context.callDepth -= 1;
                            return(null);
                        }
                    }

                    if (node.gsp("@prefix") == "^")
                    {
                        result = arguments;
                    }
                    else
                    {
                        if (arguments.Count > 0 && Function.IsFunction(arguments[0] as ScriptObject))
                        {
                            result = Function.Invoke((arguments[0] as ScriptObject), this, context,
                                                     new ScriptList(arguments.GetRange(1, arguments.Count - 1)));
                            if (context.evaluationState != EvaluationState.Normal)
                            {
                                if (context.evaluationState == EvaluationState.UnwindingError)
                                {
                                    context.PushStackTrace((arguments[0] as ScriptObject).gsp("@name"));
                                }
                                context.callDepth -= 1;
                                return(null);
                            }
                        }
                        else if (arguments.Count > 0 &&
                                 arguments[0] is ScriptObject &&
                                 (arguments[0] as ScriptObject).GetProperty("@lazy-reflection") != null)
                        {
                            var sObj          = arguments[0] as ScriptObject;
                            var argumentTypes = arguments.GetRange(1, arguments.Count - 1).Select(
                                (obj) => obj.GetType()).ToArray();
                            var sourceObject = sObj.GetProperty("@source-object");
                            var method       = (sObj.GetProperty("@source-type") as System.Type)
                                               .GetMethod(sObj.gsp("@lazy-reflection"), argumentTypes);
                            if (method == null)
                            {
                                throw new ScriptError("Could not find overload for " +
                                                      sObj.gsp("@lazy-reflection") + " that takes argument types " +
                                                      String.Join(", ", argumentTypes.Select((t) => t.Name)) + " on type " +
                                                      sObj.GetProperty("@source-type").ToString(), what as ScriptObject);
                            }
                            result = method.Invoke(sourceObject, arguments.GetRange(1, arguments.Count - 1).ToArray());
                        }
                        else if (arguments.Count > 0)
                        {
                            result = arguments[0];
                        }
                        else
                        {
                            result = null;
                        }
                    }
                }
            }
            else if (type == "root")
            {
                var results = new ScriptList();
                foreach (var child in node._children)
                {
                    results.Add(Evaluate(context, child, false, false));
                    if (context.evaluationState != EvaluationState.Normal)
                    {
                        context.callDepth -= 1;
                        return(null);
                    }
                }
                return(results);
            }
            else if (type == "number")
            {
                try
                {
                    if (node.gsp("@token").Contains('.'))
                    {
                        result = Convert.ToSingle(node.gsp("@token"));
                    }
                    else
                    {
                        var numberString = node.gsp("@token");
                        if (numberString.StartsWith("0x"))
                        {
                            result = Convert.ToInt32(numberString.Substring(2), 16);
                        }
                        else if (numberString.StartsWith("0b"))
                        {
                            var accumulator = 0;
                            foreach (var c in numberString.Substring(2))
                            {
                                accumulator <<= 1;
                                if (c == '1')
                                {
                                    accumulator += 1;
                                }
                            }
                            result = accumulator;
                        }
                        else
                        {
                            result = Int32.Parse(numberString);
                        }
                    }
                }
                catch (Exception e)
                {
                    context.RaiseNewError("Number format error.", node);
                    { context.callDepth -= 1; return(null); }
                }
            }
            else if (type == "char")
            {
                context.callDepth -= 1;
                return(node.gsp("@token")[0]);
            }
            else
            {
                context.RaiseNewError("Internal evaluator error.", node);
                { context.callDepth -= 1; return(null); }
            }

            if (node.gsp("@prefix") == ":" && !ignoreStar)
            {
                result = Evaluate(context, result);
            }
            if (context.evaluationState != EvaluationState.Normal)
            {
                context.callDepth -= 1; return(null);
            }
            ;
            if (node.gsp("@prefix") == ".")
            {
                result = LookupToken(context, ScriptObject.AsString(result));
            }
            context.callDepth -= 1;
            return(result);
        }