public override void Interpret(Operator op, FunctionBlock block)
    {
        if (ScriptEngine.AnalyzeDebug)
        {
            Debug.LogWarning("Context function " + op.Identifier);
        }
        if (exprInter == null)
        {
            exprInter = Engine.GetPlugin <ExpressionInterpreter> ();
        }
        var any        = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
        var sCtx       = block.FindStatement <ContextStatement> (v => v.InterpretInContext(op, block) != null && (v.ContextVar.IsContext || v.ContextVar.IsArg));
        var contextVar = sCtx != null ? sCtx.ContextVar : null;
        //var contextVar = block.FindStatement<DeclareVariableStatement> (v => );

        StringBuilder argsBuilder = new StringBuilder();

//		if (((op.Context is Expression) && op.Args.Count + 1 != argsDef.Length) ||
//		    ((op.Context is Context) && op.Args.Count != argsDef.Length))
//		{
//			Debug.Log ("Wrong amount of arguments");
//			return;
//		}
        for (int i = 0; i < op.Args.Count; i++)
        {
            if (argsDef [i].ParameterType.IsSubclassOf(typeof(Delegate)))
            {
                argsBuilder.Append(exprInter.InterpretClosure(op.Args [i], block, argsDef [i].ParameterType).ExprString).Append(",");
            }
            else if (argsDef [i].ParameterType == typeof(string))
            {
                argsBuilder.Append('(').Append(exprInter.InterpretExpression(op.Args [i], block).ExprString).Append(')').Append(".ToString()").Append(",");
            }
            else
            {
                argsBuilder.Append('(').Append(argsDef [i].ParameterType).Append(')').Append('(').Append(exprInter.InterpretExpression(op.Args [i], block).ExprString).Append(')').Append(",");
            }
        }
        if (op.Context is Expression)
        {
            if (argsDef [argsDef.Length - 1].ParameterType.IsSubclassOf(typeof(Delegate)))
            {
                argsBuilder.
                Append('(').
                Append(argsDef [argsDef.Length - 1].ParameterType).
                Append(')').
                Append('(').
                Append(exprInter.InterpretClosure(op.Context as Expression, block, argsDef [argsDef.Length - 1].ParameterType).ExprString).
                Append(')');
            }
            else if (argsDef [argsDef.Length - 1].ParameterType == typeof(string))
            {
                argsBuilder.Append('(').Append(exprInter.InterpretExpression(op.Context as Expression, block).ExprString).Append(')').Append(".ToString()");
            }
            else
            {
                argsBuilder.
                Append('(').
                Append(argsDef [argsDef.Length - 1].ParameterType).
                Append(')').
                Append('(').
                Append(exprInter.InterpretExpression(op.Context as Expression, block).ExprString).
                Append(')');
            }
            if (contextVar == null)
            {
                block.Statements.Add(string.Format("root.{0}({1});", funcName, argsBuilder));
            }
            else
            {
                block.Statements.Add(string.Format("{2}.{0}({1});", funcName, argsBuilder, contextVar.Name));
            }
        }
        else if (ctxInter != null)
        {
            if (op.Args.Count > 0)
            {
                argsBuilder.Length -= 1;
            }
            var           ctx          = op.Context as Context;
            FunctionBlock contextBlock = new FunctionBlock(block);
            block.Statements.Add(contextBlock);
            block = contextBlock;
            DeclareVariableStatement ctxVar = new DeclareVariableStatement();
            ctxVar.Name           = "FuncCtx" + DeclareVariableStatement.VariableId++;
            ctxVar.InitExpression = contextVar == null?string.Format("root.{0}({1});", funcName, argsBuilder) : string.Format("{2}.{0}({1});", funcName, argsBuilder, contextVar.Name);

            ctxVar.Type      = returnType;
            ctxVar.IsContext = true;

            ContextStatement stmt = new ContextStatement();
            stmt.ContextVar         = ctxVar;
            stmt.InterpretInContext = ctxInter.InterpretInContext;
            block.Statements.Add(ctxVar);
            block.Statements.Add(stmt);
            IfStatement isNotNull = new IfStatement();
            isNotNull.CheckExpression = String.Format("{0} != null", ctxVar.Name);
            isNotNull.TrueBlock       = new FunctionBlock(block);
            block.Statements.Add(isNotNull);
            block = isNotNull.TrueBlock;
            for (int i = 0; i < ctx.Entries.Count; i++)
            {
                ops.GetInterpreter(ctx.Entries [i] as Operator, block).Interpret(ctx.Entries [i] as Operator, block);
            }
        }
        else
        {
            //Func doesn't return a context, while maybe allows for either lambda as value or context addition
            var lastArg = argsDef.Length > 0 ? argsDef [argsDef.Length - 1] : null;
            if (lastArg != null)
            {
                if (typeof(Delegate).IsAssignableFrom(lastArg.ParameterType))
                {
                    Debug.Log("LAMBDA!");
                    //Interpret as lambda
                    LambdaStatement lambda = new LambdaStatement();
                    lambda.DelegateType = lastArg.ParameterType;
                    var method = lastArg.ParameterType.GetMethod("Invoke");
                    lambda.Params = method.GetParameters();
                    lambda.Name   = "Lambda" + DeclareVariableStatement.VariableId++;
                    block.Statements.Add(lambda);
                    lambda.Block = new FunctionBlock(block);

                    //DeclareVariableStatement lastVar = null;
                    foreach (var param in lambda.Params)
                    {
                        var argVar = new DeclareVariableStatement();
                        //	lastVar = argVar;
                        argVar.Name  = param.Name;
                        argVar.IsArg = true;
                        argVar.Type  = param.ParameterType;
                        lambda.Block.Statements.Add(argVar);
                    }
                    //if (lastVar != null)
                    //	lastVar.IsContext = true;

                    var  retType   = lambda.DelegateType.GetMethod("Invoke").ReturnType;
                    bool hasReturn = false;
                    if (retType != null && retType != typeof(void))
                    {
                        hasReturn = true;
                        lambda.Block.Statements.Add(new DeclareVariableStatement()
                        {
                            Name           = "return_value",
                            InitExpression = string.Format("default({0})", retType),
                            IsReturn       = true,
                            Type           = retType
                        });
                    }

                    foreach (var entry in (op.Context as Context).Entries)
                    {
                        var subOp = entry as Operator;
                        ops.GetInterpreter(subOp, lambda.Block).Interpret(subOp, lambda.Block);
                    }
                    if (hasReturn)
                    {
                        lambda.Block.Statements.Add("return return_value;");
                    }
                    //Don't forget to call a function and add an arugment
                    argsBuilder.Append(lambda.Name);
                    if (contextVar == null)
                    {
                        block.Statements.Add(string.Format("root.{0}({1});", funcName, argsBuilder));
                    }
                    else
                    {
                        block.Statements.Add(string.Format("{2}.{0}({1});", funcName, argsBuilder, contextVar.Name));
                    }
                }
                else if (addContextInter != null)
                {
                    //Interpret as new value
                    DeclareVariableStatement newVar = new DeclareVariableStatement();
                    newVar.Name      = "NewArg" + DeclareVariableStatement.VariableId++;
                    newVar.IsContext = true;
                    newVar.Type      = lastArg.ParameterType;
                    if (contextVar == null)
                    {
                        newVar.InitExpression = String.Format("root.AddComponent<{0}>()", newVar.Type);
                    }
                    else
                    {
                        newVar.InitExpression = String.Format("{0}.AddComponent<{0}>()", contextVar.Name, newVar.Type);
                    }
                    FunctionBlock contextBlock = new FunctionBlock(block);
                    contextBlock.Statements.Add(newVar);
                    addContextInter.Interpret(op, contextBlock);
                    argsBuilder.Append(newVar.Name);
                    if (contextVar == null)
                    {
                        contextBlock.Statements.Add(string.Format("root.{0}({1});", funcName, argsBuilder));
                    }
                    else
                    {
                        contextBlock.Statements.Add(string.Format("{2}.{0}({1});", funcName, argsBuilder, contextVar.Name));
                    }

                    block.Statements.Add(contextBlock);
                }
            }
        }
    }
    public override void Interpret(Operator op, FunctionBlock block)
    {
        base.Interpret(op, block);
        if (interpret)
        {
            if (ScriptEngine.AnalyzeDebug)
            {
                Debug.LogFormat("Property {0} was interpreted by ContextPropertyInterpreter {1} already", op, propName);
            }
            return;
        }
        if (!(op.Context is Context))
        {
            if (ScriptEngine.AnalyzeDebug)
            {
                Debug.LogFormat("Property context switch {0} has no context", op);
            }
            return;
        }
        if (ops == null)
        {
            ops = Engine.GetPlugin <EventFunctionOperators> ();
        }
        var varName = op.Identifier as string;

        FunctionBlock contextBlock = new FunctionBlock(block, block.Method, block.Type);

        block.Statements.Add(contextBlock);
        DeclareVariableStatement declareVar = new DeclareVariableStatement();

        declareVar.Type      = propType;
        declareVar.Name      = "subContext" + DeclareVariableStatement.VariableId++;
        declareVar.IsContext = true;

        DeclareVariableStatement contextVar = block.FindStatement <DeclareVariableStatement> (v => v.Name == varName);

        if (contextVar == null)
        {
            var sCtx = block.FindStatement <ContextStatement> (v => v.InterpretInContext(op, block) != null && v.ContextVar.IsContext);
            contextVar = sCtx != null ? sCtx.ContextVar : null;
        }

        if (contextVar == null)
        {
            declareVar.InitExpression = String.Format("root.{0}", propName);
        }
        else
        {
            declareVar.InitExpression = String.Format("{1}.{0}", propName, contextVar.Name);
        }
        contextBlock.Statements.Add(declareVar);
        contextBlock.Statements.Add(new ContextStatement()
        {
            ContextVar         = declareVar,
            InterpretInContext = InterpretInContext
        });
        IfStatement isNotNull = new IfStatement();

        isNotNull.CheckExpression = String.Format("{0} != null", declareVar.Name);
        isNotNull.TrueBlock       = new FunctionBlock(contextBlock);
        contextBlock.Statements.Add(isNotNull);
        contextBlock = isNotNull.TrueBlock;
        foreach (var entry in (op.Context as Context).Entries)
        {
            //Debug.LogFormat("Interpreting {0} as part of {1} context", (entry as Operator).Identifier, op.Identifier);
            var subOp = entry as Operator;
            if (subOp == null)
            {
                continue;
            }
            FunctionOperatorInterpreter opInter = null;
            if ((opInter = ops.GetInterpreter(subOp, contextBlock)) == null)
            {
                if (!contextSwitches.TryGetValue(subOp.Identifier as string, out opInter))
                {
                    if (!functions.TryGetValue(subOp.Identifier as string, out opInter))
                    {
                        if (!properties.TryGetValue(subOp.Identifier as string, out opInter))
                        {
                            //Debug.LogFormat ("Can't interpret context operator {1} in {0}", block.Method.Name, subOp.Identifier);
                            continue;
                        }
                    }
                }
            }
            opInter.Interpret(subOp, contextBlock);
        }
    }
    public override void Interpret(Operator op, FunctionBlock block)
    {
        if (ops == null)
        {
            ops = Engine.GetPlugin <EventFunctionOperators> ();
        }
        FunctionBlock contextBlock = new FunctionBlock(block, block.Method, block.Type);

        block.Statements.Add(contextBlock);
        DeclareVariableStatement addVar = block.FindStatement <DeclareVariableStatement> (v => v.Name == op.Identifier as string);
        bool setContext = false;

        if (addVar != null && !addVar.IsContext)
        {
            setContext = addVar.IsContext = true;
        }
        if (addVar == null)
        {
            addVar = block.FindStatement <DeclareVariableStatement> (v => v.IsContext && v.Type == contextType);
        }
        //TODO: probably will fail
        DeclareVariableStatement contextVar = contextType == typeof(GameObject)? addVar : block.FindStatement <DeclareVariableStatement> (v => v.IsContext && v.Type == typeof(GameObject) && v != addVar);
        DeclareVariableStatement declareVar = null;

        if (addVar == null)
        {
            declareVar           = new DeclareVariableStatement();
            declareVar.Type      = contextType;
            declareVar.Name      = "subContext" + DeclareVariableStatement.VariableId++;
            declareVar.IsContext = true;

            if (contextVar == null)
            {
                declareVar.InitExpression = String.Format("({0})root.GetComponent(typeof({0}))", contextType);
            }
            else
            {
                declareVar.InitExpression = String.Format("({0}){1}.GetComponent(typeof({0}))", contextType, contextVar.Name);
            }
            contextBlock.Statements.Add(declareVar);
        }
        else
        {
            declareVar = addVar;
        }

        contextBlock.Statements.Add(new ContextStatement()
        {
            ContextVar         = declareVar,
            InterpretInContext = InterpretInContext
        });
        IfStatement isNotNull = new IfStatement();

        isNotNull.CheckExpression = String.Format("{0} != null", declareVar.Name);
        isNotNull.TrueBlock       = new FunctionBlock(contextBlock);
        contextBlock.Statements.Add(isNotNull);
        contextBlock = isNotNull.TrueBlock;
        contextBlock.Statements.Add(new DeclareVariableStatement()
        {
            Name = declareVar.Name, IsArg = true, IsContext = true, Type = declareVar.Type
        });
        foreach (var entry in (op.Context as Context).Entries)
        {
            var subOp = entry as Operator;
            if (subOp == null)
            {
                continue;
            }
            FunctionOperatorInterpreter opInter = null;

            if ((opInter = ops.GetInterpreter(subOp, contextBlock)) == null)
            {
                if (!contextSwitches.TryGetValue(subOp.Identifier as string, out opInter))
                {
                    if (!functions.TryGetValue(subOp.Identifier as string, out opInter))
                    {
                        if (!properties.TryGetValue(subOp.Identifier as string, out opInter))
                        {
                            Debug.LogWarningFormat("Can't interpret context operator {1} in {0}", block.Method.Name, subOp.Identifier);
                            continue;
                        }
                    }
                }
            }
            if (ScriptEngine.AnalyzeDebug)
            {
                Debug.LogFormat("Interpret {0} via {1}", subOp.Identifier, opInter);
            }
            opInter.Interpret(subOp, contextBlock);
        }

        if (setContext)
        {
            addVar.IsContext = false;
        }
    }