Beispiel #1
0
        private Function defunImple(Context context, ScriptList arguments, bool addToScope)
        {
            var functionName = ArgumentType<String>(arguments[0]);

            List<ArgumentInfo> argumentInfo = null;
            try
            {
                argumentInfo = ArgumentInfo.ParseArguments(this, ArgumentType<ScriptList>(arguments[1]));
            }
            catch (ScriptError e)
            {
                context.RaiseNewError(e.Message, context.currentNode);
                return null;
            }

            var functionBody = ArgumentType<ParseNode>(arguments[2]);

            var newFunction = new Function(
                functionName,
                argumentInfo,
                "Script-defined function",
                functionBody,
                CopyScope(context.Scope));

            newFunction.shortHelp = ScriptObject.AsString(arguments[3]);

            if (addToScope) newFunction.declarationScope.PushVariable(newFunction.name, newFunction);

            return newFunction;
        }
Beispiel #2
0
        private ScriptObject defunImple(Context context, ScriptList arguments, bool addToScope)
        {
            var functionName = ArgumentType<String>(arguments[0]);

            ScriptList argumentInfo = null;
            try
            {
                argumentInfo = ArgumentType<ScriptList>(arguments[1]);
            }
            catch (ScriptError e)
            {
                context.RaiseNewError(e.Message, context.currentNode);
                return null;
            }

            var functionBody = ArgumentType<ScriptObject>(arguments[2]);

            var newFunction = Function.MakeFunction(
                functionName,
                argumentInfo,
                "Script-defined function",
                functionBody,
                CopyScope(context.Scope));

            if (arguments[3] != null) newFunction["@help"] = ScriptObject.AsString(arguments[3]);

            if (addToScope) (newFunction["declaration-scope"] as Scope).PushVariable(functionName, newFunction);

            return newFunction;
        }
Beispiel #3
0
 private static object SetObjectProperty(Context context, Object obj, String name, Object value)
 {
     if (obj is ScriptObject)
     {
         try
         {
             (obj as ScriptObject)[name] = value;
         }
         catch (Exception e)
         {
             context.RaiseNewError("System Exception: " + e.Message, context.currentNode);
         }
     }
     else
     {
         var field = obj.GetType().GetField(ScriptObject.AsString(name));
         if (field != null) field.SetValue(obj, value);
         else
         {
             var prop = obj.GetType().GetProperty(ScriptObject.AsString(name));
             if (prop != null) prop.SetValue(obj, value, null);
         }
     }
     return value;
 }
Beispiel #4
0
        public static ScriptObject GetArgumentInfo(ScriptObject func, Context context, int index)
        {
            var arguments = func["@arguments"] as ScriptList;

            if (arguments == null)
            {
                return(null);
            }

            if (index >= arguments.Count)
            {
                if (arguments.Count > 0 && (arguments[arguments.Count - 1] as ScriptObject)["@repeat"] != null)
                {
                    return(arguments[arguments.Count - 1] as ScriptObject);
                }
                else
                {
                    context.RaiseNewError("Argument out of bounds", null);
                    return(null);
                }
            }
            else
            {
                return(arguments[index] as ScriptObject);
            }
        }
Beispiel #5
0
 public Object EvaluateString(Context context, String str, String fileName, bool discardResults = false)
 {
     try
     {
         var root = Parser.ParseRoot(str, fileName);
         return(Evaluate(context, root, false, discardResults));
     }
     catch (Exception e)
     {
         context.RaiseNewError("System Exception: " + e.Message, null);
         return(null);
     }
 }
Beispiel #6
0
 private static object SetObjectProperty(Context context, Object obj, String name, Object value)
 {
     if (obj is ScriptObject)
     {
         try
         {
             (obj as ScriptObject)[name] = value;
         }
         catch (Exception e)
         {
             context.RaiseNewError("System Exception: " + e.Message, context.currentNode);
         }
     }
     else
     {
         var field = obj.GetType().GetField(ScriptObject.AsString(name));
         if (field != null)
         {
             field.SetValue(obj, value);
         }
         else
         {
             var prop = obj.GetType().GetProperty(ScriptObject.AsString(name));
             if (prop != null)
             {
                 prop.SetValue(obj, value, null);
             }
             else
             {
                 context.RaiseNewError("Could not find member with name '" + ScriptObject.AsString(name) + "' on object" +
                                       " of type '" + obj.GetType().ToString() + "'", context.currentNode);
             }
         }
     }
     return(value);
 }
Beispiel #7
0
        public static ScriptObject GetArgumentInfo(ScriptObject func, Context context, int index)
        {
            var arguments = func["@arguments"] as ScriptList;
            if (arguments == null) return null;

            if (index >= arguments.Count)
            {
                if (arguments.Count > 0 && (arguments[arguments.Count - 1] as ScriptObject)["@repeat"] != null)
                    return arguments[arguments.Count - 1] as ScriptObject;
                else
                {
                    context.RaiseNewError("Argument out of bounds", null);
                    return null;
                }
            }
            else
                return arguments[index] as ScriptObject;
        }
Beispiel #8
0
 private object LookupToken(Context context, String value)
 {
     //value = value.ToLowerInvariant();
     if (specialVariables.ContainsKey(value))
     {
         return(specialVariables[value](context));
     }
     if (context.Scope.HasVariable(value))
     {
         return(context.Scope.GetVariable(value));
     }
     if (functions.ContainsKey(value))
     {
         return(functions[value]);
     }
     if (value.StartsWith("@") && functions.ContainsKey(value.Substring(1)))
     {
         return(functions[value.Substring(1)]);
     }
     context.RaiseNewError("Could not find value with name " + value + " in this context.", context.currentNode);
     return(null);
 }
Beispiel #9
0
        private ScriptObject defunImple(Context context, ScriptList arguments, bool addToScope)
        {
            var functionName = ArgumentType <String>(arguments[0]);

            ScriptList argumentInfo = null;

            try
            {
                argumentInfo = ArgumentType <ScriptList>(arguments[1]);
            }
            catch (ScriptError e)
            {
                context.RaiseNewError(e.Message, context.currentNode);
                return(null);
            }

            var functionBody = ArgumentType <ScriptObject>(arguments[2]);

            var newFunction = Function.MakeFunction(
                functionName,
                argumentInfo,
                "Script-defined function",
                functionBody,
                CopyScope(context.Scope));

            if (arguments[3] != null)
            {
                newFunction["@help"] = ScriptObject.AsString(arguments[3]);
            }

            if (addToScope)
            {
                (newFunction["declaration-scope"] as Scope).PushVariable(functionName, newFunction);
            }

            return(newFunction);
        }
Beispiel #10
0
 private object LookupToken(Context context, String value)
 {
     //value = value.ToLowerInvariant();
     if (specialVariables.ContainsKey(value)) return specialVariables[value](context);
     if (context.Scope.HasVariable(value)) return context.Scope.GetVariable(value);
     if (functions.ContainsKey(value)) return functions[value];
     if (value.StartsWith("@") && functions.ContainsKey(value.Substring(1))) return functions[value.Substring(1)];
     context.RaiseNewError("Could not find value with name " + value + " in this context.", context.currentNode);
     return null;
 }
Beispiel #11
0
 public Object EvaluateString(Context context, String str, String fileName, bool discardResults = false)
 {
     try
     {
         var root = Parser.ParseRoot(str, fileName);
         return Evaluate(context, root, false, discardResults);
     }
     catch (Exception e)
     {
         context.RaiseNewError("System Exception: " + e.Message, null);
         return null;
     }
 }
Beispiel #12
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 #13
0
        public static Object Invoke(ScriptObject func, Engine engine, Context context, ScriptList arguments)
        {
            var name = func.gsp("@name");
            var argumentInfo = func["@arguments"] as ScriptList;

            if (context.trace != null)
            {
                context.trace(new String('.', context.traceDepth) + "Entering " + name +"\n");
                context.traceDepth += 1;
            }

            var newArguments = new ScriptList();
            //Check argument types
            if (argumentInfo.Count == 0 && arguments.Count != 0)
            {
                context.RaiseNewError("Function expects no arguments.", context.currentNode);
                return null;
            }

                int argumentIndex = 0;
                for (int i = 0; i < argumentInfo.Count; ++i)
                {
                    var info = argumentInfo[i] as ScriptObject;
                    if (info == null)
                        throw new ScriptError("Invalid argument descriptor on function object", context.currentNode);
                    if (info["@repeat"] != null)
                    {
                        var list = new ScriptList();
                        while (argumentIndex < arguments.Count) //Handy side effect: If no argument is passed for an optional repeat
                        {                                       //argument, it will get an empty list.
                            list.Add(MutateArgument(arguments[argumentIndex], info, engine, context));
                            //list.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex]));
                            if (context.evaluationState != EvaluationState.Normal) return null;
                            ++argumentIndex;
                        }
                        newArguments.Add(list);
                    }
                    else
                    {
                        if (argumentIndex < arguments.Count)
                        {
                            newArguments.Add(MutateArgument(arguments[argumentIndex], info, engine, context));
                            //newArguments.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex]));
                            if (context.evaluationState == EvaluationState.UnwindingError) return null;
                        }
                        else if (info["@optional"] != null)
                            newArguments.Add(MutateArgument(null, info, engine, context));
                        else
                        {
                            context.RaiseNewError("Not enough arguments to " + name, context.currentNode);
                            return null;
                        }
                        ++argumentIndex;
                    }
                }
                if (argumentIndex < arguments.Count)
                {
                    context.RaiseNewError("Too many arguments to " + name, context.currentNode);
                    return null;
                }

            Object r = null;

            if (func["@function-body"] is ScriptObject)
            {
                var declarationScope = func["@declaration-scope"];
                if (declarationScope is GenericScriptObject)
                {
                    var newScope = new Scope();
                    foreach (var valueName in (declarationScope as GenericScriptObject).properties)
                        newScope.PushVariable(valueName.Key, valueName.Value);
                    func["@declaration-scope"] = newScope;
                }

                context.PushScope(func["@declaration-scope"] as Scope);

                for (int i = 0; i < argumentInfo.Count; ++i)
                    context.Scope.PushVariable((argumentInfo[i] as ScriptObject).gsp("@name"), newArguments[i]);

                r = engine.Evaluate(context, func["@function-body"], true);

                for (int i = 0; i < argumentInfo.Count; ++i)
                    context.Scope.PopVariable((argumentInfo[i] as ScriptObject).gsp("@name"));

                context.PopScope();
            }
            else
            {
                try
                {
                    r = (func["@function-body"] as Func<Context, ScriptList, Object>)(context, newArguments);
                }
                catch (Exception e)
                {
                    context.RaiseNewError("System Exception: " + e.Message, context.currentNode);
                    return null;
                }
            }

            if (context.trace != null)
            {
                context.traceDepth -= 1;
                context.trace(new String('.', context.traceDepth) + "Leaving " + name +
                    (context.evaluationState == EvaluationState.UnwindingError ?
                    (" -Error: " + context.errorObject.GetLocalProperty("message").ToString()) :
                    "") +
                    (context.evaluationState == EvaluationState.UnwindingBreak ? " -Breaking" : "") +
                    "\n");
            }

            return r;
        }
Beispiel #14
0
        public static Object Invoke(ScriptObject func, Engine engine, Context context, ScriptList arguments)
        {
            var name         = func.gsp("@name");
            var argumentInfo = func["@arguments"] as ScriptList;

            if (context.trace != null)
            {
                context.trace(new String('.', context.traceDepth) + "Entering " + name + "\n");
                context.traceDepth += 1;
            }

            var newArguments = new ScriptList();

            //Check argument types
            if (argumentInfo.Count == 0 && arguments.Count != 0)
            {
                context.RaiseNewError("Function expects no arguments.", context.currentNode);
                return(null);
            }

            int argumentIndex = 0;

            for (int i = 0; i < argumentInfo.Count; ++i)
            {
                var info = argumentInfo[i] as ScriptObject;
                if (info == null)
                {
                    throw new ScriptError("Invalid argument descriptor on function object", context.currentNode);
                }
                if (info["@repeat"] != null)
                {
                    var list = new ScriptList();
                    while (argumentIndex < arguments.Count)     //Handy side effect: If no argument is passed for an optional repeat
                    {                                           //argument, it will get an empty list.
                        list.Add(MutateArgument(arguments[argumentIndex], info, engine, context));
                        //list.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex]));
                        if (context.evaluationState != EvaluationState.Normal)
                        {
                            return(null);
                        }
                        ++argumentIndex;
                    }
                    newArguments.Add(list);
                }
                else
                {
                    if (argumentIndex < arguments.Count)
                    {
                        newArguments.Add(MutateArgument(arguments[argumentIndex], info, engine, context));
                        //newArguments.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex]));
                        if (context.evaluationState == EvaluationState.UnwindingError)
                        {
                            return(null);
                        }
                    }
                    else if (info["@optional"] != null)
                    {
                        newArguments.Add(MutateArgument(null, info, engine, context));
                    }
                    else
                    {
                        context.RaiseNewError("Not enough arguments to " + name, context.currentNode);
                        return(null);
                    }
                    ++argumentIndex;
                }
            }
            if (argumentIndex < arguments.Count)
            {
                context.RaiseNewError("Too many arguments to " + name, context.currentNode);
                return(null);
            }


            Object r = null;

            if (func["@function-body"] is ScriptObject)
            {
                var declarationScope = func["@declaration-scope"];
                if (declarationScope is GenericScriptObject)
                {
                    var newScope = new Scope();
                    foreach (var valueName in (declarationScope as GenericScriptObject).properties)
                    {
                        newScope.PushVariable(valueName.Key, valueName.Value);
                    }
                    func["@declaration-scope"] = newScope;
                }

                context.PushScope(func["@declaration-scope"] as Scope);

                for (int i = 0; i < argumentInfo.Count; ++i)
                {
                    context.Scope.PushVariable((argumentInfo[i] as ScriptObject).gsp("@name"), newArguments[i]);
                }

                r = engine.Evaluate(context, func["@function-body"], true);

                for (int i = 0; i < argumentInfo.Count; ++i)
                {
                    context.Scope.PopVariable((argumentInfo[i] as ScriptObject).gsp("@name"));
                }

                context.PopScope();
            }
            else
            {
                try
                {
                    r = (func["@function-body"] as Func <Context, ScriptList, Object>)(context, newArguments);
                }
                catch (Exception e)
                {
                    context.RaiseNewError("System Exception: " + e.Message, context.currentNode);
                    return(null);
                }
            }


            if (context.trace != null)
            {
                context.traceDepth -= 1;
                context.trace(new String('.', context.traceDepth) + "Leaving " + name +
                              (context.evaluationState == EvaluationState.UnwindingError ?
                               (" -Error: " + context.errorObject.GetLocalProperty("message").ToString()) :
                               "") +
                              (context.evaluationState == EvaluationState.UnwindingBreak ? " -Breaking" : "") +
                              "\n");
            }

            return(r);
        }
Beispiel #15
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);
        }