using System;
using System.Collections.Generic;
using System.Linq;

namespace DotPrograms
{
    [Serializable]
    public partial class ParseTreeEvaluator : ParseTreeEvaluatorOriginal
    {
        #region Fields

        public Dictionary<string, Function> functions = new Dictionary<string, Function>();
        private Dictionary<TokenType, OperationConfiguration> operatorOperations = new Dictionary<TokenType, OperationConfiguration>();
        private Scanner scanner;

        #endregion

        #region Static fields

        private const string OPCFG_NAME_JUMP = "jump";
        private const string OPCFG_NAME_JUMP_IF = "jumpif";
        private const string OPCFG_NAME_SET_CONSTANT = "setconstant";

        #endregion

        #region Constructors

        //public ParseTreeEvaluator() : base()
        //{
        //}
        public ParseTreeEvaluator(Context context, Scanner scanner) : base(context)
        {
            this.scanner = scanner;

            #region Fixed functions

            #region jump

            this.functions.Add("jump", new StaticFunction("Jump",
                delegate(object[] ps)
                {
                    if (ps.Length == 1)
                    {
                        if (this.Context.DotOperations.ContainsKey(OPCFG_NAME_JUMP) == true)
                        {
                            Operation operation = new LabelOperation((byte)this.Context.DotOperations[OPCFG_NAME_JUMP].OperationCode, (string)ps[0]);
                            byte opcode = (byte)operation.OperationCode;

                            operation.BytesCode.Add(new byte[] { opcode, 1, });

                            return new FunctionResult(operation);
                        }
                        else
                        {
                            throw new CompilationException(
                                string.Format(
                                    "Missing operation configuration for '{0}' function.",
                                    OPCFG_NAME_JUMP
                                )
                            );
                        }
                    }
                    else
                    {
                        if (this.Context.DotOperations.ContainsKey(OPCFG_NAME_JUMP_IF) == true)
                        {
                            Operation operation = new LabelOperation((byte)this.Context.DotOperations[OPCFG_NAME_JUMP_IF].OperationCode, (string)ps[1]);
                            byte opcode = (byte)operation.OperationCode;

                            operation.BytesCode.Add(
                                new byte[]
                            {
                                opcode, 
                                (ps[0] is IStackValue) ? ((IStackValue)ps[0]).StackPosition : Convert.ToByte(ps[0]), 
                                1,
                            }
                            );

                            return new FunctionResult(operation);
                        }
                        else
                        {
                            throw new CompilationException(
                                string.Format(
                                    "Missing operation configuration for '{0}' function.",
                                    OPCFG_NAME_JUMP_IF
                                )
                            );
                        }
                    }
                },
                1,
                2
            ));

            #endregion

            #endregion


            var scannerPatterns = this.scanner.Patterns.ToList();

            this.Context.DotOperations
                .ToList()
                .ForEach(kvp =>
                {
                    var pattern = scannerPatterns.FirstOrDefault(spkvp => spkvp.Value.IsMatch(kvp.Key));

                    if ((pattern.Key != null) && (pattern.Key != TokenType.VARIABLE))
                    {
                        this.operatorOperations.Add(pattern.Key, kvp.Value);
                    }
                    else
                    {
                        if (this.functions.ContainsKey(kvp.Key) == false)
                        {
                            this.functions.Add(kvp.Key, new ConfigurableFunction(kvp.Key,
                                delegate(object[] ps, OperationConfiguration opcfg)
                                {
                                    return this.EvalDotOperation(ps, opcfg);
                                },
                                kvp.Value
                            ));
                        }
                    }
                });
        }

        #endregion

        #region Methods

        public override ParseNode CreateNode(Token token, string text)
        {
            ParseTreeEvaluator node = new ParseTreeEvaluator(this.Context, this.scanner);
            node.Token = token;
            node.text = text;
            node.Parent = this;
            return node;
        }
        public override object Eval(params object[] paramlist)
        {
            //ParseTree.Operations = new List<byte[]>();

            //return Nodes[0].Eval(this, paramlist);




            //FunctionResult result = (FunctionResult)Nodes[0].Eval(this, paramlist);


            object value = Nodes[0].Eval(this, paramlist);

            //if (!(value is FunctionResult))
            //    return value;
            //else
            //    return "";


            if (value is FunctionResult)
            {
                FunctionResult result = (FunctionResult)value;

                if (result.ResolvedLocally == false)
                {
                    string str = "";

                    if (result.Operation != null)
                        result.Operation.BytesCode.ForEach(op => str += "[" + string.Join(",", op) + "],");

                    return str;
                }
                else
                {
                    return result.LocalValue;
                }
            }
            if (value is GlobalVariable)
            {
                GlobalVariable global = (GlobalVariable)value;

                if (this.Context.LocalVariables.ContainsKey(global.Token) == false)
                    return global.StackPosition;
                else
                    return this.Context.LocalVariables[global.Token];
            }
            else
            {
                return value;
            }
        }
        protected override object EvalUnaryExpression(ParseTree tree, params object[] paramlist)
        {
            TokenType type = this.nodes[0].Token.Type;
            if (type == TokenType.PrimaryExpression)
                return this.GetValue(tree, TokenType.PrimaryExpression, 0);

            if (type == TokenType.NOT)
            {
                object p = this.GetValue(tree, TokenType.UnaryExpression, 0);

                return this.EvalDotOperation(new object[] { p, }, this.nodes[0].Token);
            }
            else
            {
                return null;
            }
        }
        protected override object EvalFunction(ParseTree tree, params object[] paramlist)
        {
            ParseNode funcNode = this.nodes[0];
            ParseNode paramNode = this.nodes[2];

            ParseTreeEvaluator root = tree as ParseTreeEvaluator;
            if (root == null)
            {
                tree.Errors.Add(new ParseError("Invalid parser used", 1040, this));
                return null;
            }
            if (root.Context == null)
            {
                tree.Errors.Add(new ParseError("No context defined", 1041, this));
                return null;
            }
            if (root.Context.CurrentStackSize > 50)
            {
                tree.Errors.Add(new ParseError("Stack overflow: " + funcNode.Token.Text + "()", 1046, this));
                return null;
            }
            string key = funcNode.Token.Text.ToLowerInvariant();
            if (!root.functions.ContainsKey(key))
            {
                tree.Errors.Add(new ParseError("Fuction not defined: " + funcNode.Token.Text + "()", 1042, this));
                return null;
            }

            // retrieves the function from declared functions
            Function func = root.functions[key];

            // evaluate the function parameters
            object[] parameters = new object[0];
            if (paramNode.Token.Type == TokenType.Params)
                parameters = (paramNode.Eval(tree, paramlist) as List<object>).ToArray();
            if (parameters.Length < func.MinParameters)
            {
                tree.Errors.Add(new ParseError("At least " + func.MinParameters.ToString() + " parameter(s) expected", 1043, this));
                return null; // illegal number of parameters
            }
            else if ((func.MaxParameters != -1) && (parameters.Length > func.MaxParameters))
            {
                tree.Errors.Add(new ParseError("No more than " + func.MaxParameters.ToString() + " parameter(s) expected", 1044, this));
                return null; // illegal number of parameters
            }



            object value = func.Eval(parameters, root);

            if (value is FunctionResult)
                root.Context.Operations.Add(((FunctionResult)value).Operation);
            //root.Context.Operations.AddRange(((FunctionResult)value).Operations);

            return value;

            //return func.Eval(parameters, root);
        }
        protected override object EvalVariable(ParseTree tree, params object[] paramlist)
        {
            ParseTreeEvaluator root = tree as ParseTreeEvaluator;
            if (root == null)
            {
                tree.Errors.Add(new ParseError("Invalid parser used", 1040, this));
                return null;
            }
            if (root.Context == null)
            {
                tree.Errors.Add(new ParseError("No context defined", 1041, this));
                return null;
            }

            string key = this.nodes[0].Token.Text;
            // first check if the variable was declared in scope of a function
            if (root.Context.CurrentScope != null && root.Context.CurrentScope.ContainsKey(key))
                return root.Context.CurrentScope[key];


            // if not in scope of a function
            // next check if the variable is local
            if (root.Context.LocalVariables.ContainsKey(key) == true)
                return root.Context.LocalVariables[key];


            // if not local
            // next check if the variable was declared as a global variable
            if (root.Context.Globals != null && root.Context.Globals.ContainsKey(key))
                return root.Context.Globals[key];

            //variable not found
            tree.Errors.Add(new ParseError("Variable not defined: " + key, 1039, this));
            return null;
        }
        protected override object EvalLabel(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.Variable, 0);

            if (nodes.Count > 0)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 0; k < nodes.Count; k += 1)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k].Eval(tree, paramlist);

                    if (token.Type == TokenType.LABEL)
                    {
                        Operation operation = new LabelOperation((byte)OperationCodes.Label, ((string)param2).Replace("::", ""));

                        root.Context.Operations.Add(operation);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalPowerExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.UnaryExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                // IMPORTANT: scanning and calculating the power is done from Left to Right.
                // this is conform the Excel evaluation of power, but not conform strict mathematical guidelines
                // this means that a^b^c evaluates to (a^b)^c  (Excel uses the same kind of evaluation)
                // stricly mathematical speaking a^b^c should evaluate to a^(b^c) (therefore calculating the powers from Right to Left)
                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if (token.Type == TokenType.POWER)
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalMultiplicativeExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.PowerExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if ((token.Type == TokenType.ASTERIKS) || (token.Type == TokenType.SLASH) || (token.Type == TokenType.PERCENT))
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalAdditiveExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.MultiplicativeExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if ((token.Type == TokenType.PLUS) || (token.Type == TokenType.MINUS))
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalRelationalExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.ConcatEpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if ((token.Type == TokenType.LESSTHAN) || (token.Type == TokenType.LESSEQUAL)
                        || (token.Type == TokenType.GREATERTHAN) || (token.Type == TokenType.GREATEREQUAL))
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalEqualityExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.RelationalExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if ((token.Type == TokenType.EQUAL) || (token.Type == TokenType.NOTEQUAL))
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalConditionalAndExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.EqualityExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if (token.Type == TokenType.AMPAMP)
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }        
        protected override object EvalConditionalOrExpression(ParseTree tree, params object[] paramlist)
        {
            object param1 = this.GetValue(tree, TokenType.ConditionalAndExpression, 0);

            if (nodes.Count > 1)
            {
                ParseTreeEvaluator root = tree as ParseTreeEvaluator;
                FunctionResult result = new FunctionResult();

                for (int k = 1; k < nodes.Count; k += 2)
                {
                    Token token = nodes[k].Token;
                    object param2 = nodes[k + 1].Eval(tree, paramlist);

                    if (token.Type == TokenType.PIPEPIPE)
                    {
                        result = this.EvalDotOperation(new object[] { param1, param2, }, token);

                        param1 = result;
                    }
                }

                return result;
            }
            else
            {
                return param1;
            }
        }
        protected override object EvalExpression(ParseTree tree, params object[] paramlist)
        {
            // if only left hand side available, this is not an assignment, simple evaluate expression
            if (nodes.Count == 1)
                return this.GetValue(tree, TokenType.AssignmentExpression, 0); // return the result

            if (nodes.Count != 3)
            {
                tree.Errors.Add(new ParseError("Illegal EvalExpression format", 1092, this));
                return null;
            }

            // ok, this is an assignment so declare the function or variable
            // assignment only allowed to function or to a variable
            ParseNode v = GetFunctionOrVariable(nodes[0]);
            if (v == null)
            {
                tree.Errors.Add(new ParseError("Can only assign to function or variable", 1020, this));
                return null;
            }

            ParseTreeEvaluator root = tree as ParseTreeEvaluator;
            if (root == null)
            {
                tree.Errors.Add(new ParseError("Invalid parser used", 1040, this));
                return null;
            }

            if (root.Context == null)
            {
                tree.Errors.Add(new ParseError("No context defined", 1041, this));
                return null;
            }

            if (v.Token.Type == TokenType.VARIABLE)
            {

                // simply overwrite any previous defnition
                string key = v.Token.Text;
                //root.Context.Globals[key] = this.GetValue(tree, TokenType.AssignmentExpression, 1);

                object value = this.GetValue(tree, TokenType.AssignmentExpression, 1);

                //root.Context.Globals[key] = value;


                if (value is FunctionResult)
                {
                    FunctionResult funcResult = (FunctionResult)value;


                    if (funcResult.ResolvedLocally == false)
                    {
                        if (this.operatorOperations.ContainsKey(TokenType.ASSIGN) == true)
                        {
                            Operation op = new Operation((byte)this.operatorOperations[TokenType.ASSIGN].OperationCode);
                            op.BytesCode.Add(new byte[] { 
                                (byte)op.OperationCode, 
                                Convert.ToByte(((GlobalVariable)root.Context.Globals[key]).StackPosition), 
                                funcResult.StackPosition, 
                            });

                            root.Context.Operations.Add(op);

                            //Remove it from local variables
                            if (root.Context.LocalVariables.ContainsKey(key) == true)
                                root.Context.LocalVariables.Remove(key);

                            //Release stack pos of result.
                            root.Context.ReleaseStackVar(funcResult.StackPosition);
                        }
                        else
                        {
                            throw new CompilationException(
                                string.Format(
                                    "Missing operation configuration for operator '{0}'.",
                                    this.scanner.Scan(TokenType.ASSIGN).Text
                                )
                            );
                        }
                    }
                    else
                    {
                        root.Context.LocalVariables[key] = funcResult.LocalValue;

                        if (this.Context.DotOperations.ContainsKey(OPCFG_NAME_SET_CONSTANT) == true)
                        {
                            byte[] floatBytes = BitConverter.GetBytes(Convert.ToSingle(funcResult.LocalValue));

                            Operation op = new Operation((byte)this.Context.DotOperations[OPCFG_NAME_SET_CONSTANT].OperationCode);
                            op.BytesCode.Add(new byte[] { 
                                (byte)op.OperationCode, 
                                Convert.ToByte(((GlobalVariable)root.Context.Globals[key]).StackPosition), 
                                floatBytes[0],
                                floatBytes[1],
                                floatBytes[2],
                                floatBytes[3],
                            });

                            root.Context.Operations.Add(op);
                        }
                        else
                        {
                            throw new CompilationException(
                                string.Format(
                                    "Missing operation configuration for '{0}' function.",
                                    OPCFG_NAME_SET_CONSTANT
                                )
                            );
                        }
                    }
                }
                else
                {
                    root.Context.LocalVariables[key] = value;

                        if (this.Context.DotOperations.ContainsKey(OPCFG_NAME_SET_CONSTANT) == true)
                        {
                            byte[] floatBytes = BitConverter.GetBytes(Convert.ToSingle(value));

                            Operation op = new Operation((byte)this.Context.DotOperations[OPCFG_NAME_SET_CONSTANT].OperationCode);
                            op.BytesCode.Add(new byte[] { 
                                (byte)op.OperationCode, 
                                Convert.ToByte(((GlobalVariable)root.Context.Globals[key]).StackPosition),
                                floatBytes[0],
                                floatBytes[1],
                                floatBytes[2],
                                floatBytes[3],
                            });

                            root.Context.Operations.Add(op);
                        }
                        else
                        {
                            throw new CompilationException(
                                string.Format(
                                    "Missing operation configuration for '{0}' function.",
                                    OPCFG_NAME_SET_CONSTANT
                                )
                            );
                        }
                }


                //if (value is FunctionResult)
                //{
                //    FunctionResult funcResult = (FunctionResult)value;

                //    root.Context.Globals[key] = funcResult;
                //}
                //else
                //{
                //    root.Context.Globals[key] = value;
                //}


                return null;
            }
            else if (v.Token.Type == TokenType.Function)
            {

                string key = v.Nodes[0].Token.Text;

                // function lookup is case insensitive
                if (root.functions.ContainsKey(key.ToLower()))
                    if (!(root.functions[key.ToLower()] is DynamicFunction))
                    {
                        tree.Errors.Add(new ParseError("Built in functions cannot be overwritten", 1050, this));
                        return null;
                    }

                // lets determine the input variables. 
                // functions must be of te form f(x;y;z) = x+y*z;
                // check the function parameters to be of type Variable, error otherwise
                Variables vars = new Variables();
                ParseNode paramsNode = v.Nodes[2];
                if (paramsNode.Token.Type == TokenType.Params)
                {   // function has parameters, so check if they are all variable declarations
                    for (int i = 0; i < paramsNode.Nodes.Count; i += 2)
                    {
                        ParseNode varNode = GetFunctionOrVariable(paramsNode.Nodes[i]);
                        if (varNode == null || varNode.Token.Type != TokenType.VARIABLE)
                        {
                            tree.Errors.Add(new ParseError("Function declaration may only contain variables", 1051, this));
                            return null;
                        }
                        // simply declare the variable, no need to evaluate the value of it at this point. 
                        // evaluation will be done when the function is executed
                        // note, variables are Case Sensitive (!)

                        vars.Add(varNode.Token.Text, null);
                    }
                }
                // we have all the info we need to know to declare the dynamicly defined function
                // pass on nodes[2] which is the Right Hand Side (RHS) of the assignment
                // nodes[2] will be evaluated at runtime when the function is executed.
                DynamicFunction dynf = new DynamicFunction(key, nodes[2], vars, vars.Count, vars.Count);
                root.functions[key.ToLower()] = dynf;
                return null;
            }



            // in an assignment, dont return any result (basically void)
            return null;
        }

        private FunctionResult EvalDotOperation(object[] ps, Token token)
        {
            if (this.operatorOperations.ContainsKey(token.Type) == true)
            {
                FunctionResult result = this.EvalDotOperation(ps, this.operatorOperations[token.Type]);

                this.Context.Operations.Add(result.Operation);

                return result;
            }
            else
            {
                throw new CompilationException(string.Format("Missing operation configuration for operator '{0}'.", token.Text));
            }
        }
        private FunctionResult EvalDotOperation(object[] ps, OperationConfiguration opcfg)
        {
            Operation operation = new Operation(opcfg.OperationCode);
            byte? stackPos = null;
            //int bytesCodeMaxParams = 1 + opcfg.ParametersCount;
            int i;

            FunctionResult result = new FunctionResult(operation);
            byte opcode = (byte)operation.OperationCode;

            List<byte> bytesCode;

            //List<List<byte>> bytesCodes = new List<List<byte>>();
            int fullLen = ps.GetLength(0);
            object p;

            bytesCode = new List<byte> { opcode };


            //Release stack pos of current function using one of the parameters if it is possible.
            for (i = 0; i < fullLen; i++)
            {
                p = ps[i];

                if (p is FunctionResult)
                {
                    stackPos = ((FunctionResult)p).StackPosition;
                    break;
                }
            }


            //Check if one of the parameters is a global variable.
            for (i = 0; i < fullLen; i++)
            {
                p = ps[i];

                if (p is GlobalVariable)
                {
                    //Set function result as not resolved locally because at least one of the function
                    //parameters is a global variable or a function result.
                    result.ResolvedLocally = false;

                    break;
                }
                else if ((p is FunctionResult) && (((FunctionResult)p).ResolvedLocally == false))
                {
                    //Set function result as not resolved locally because at least one of the function
                    //parameters is a global variable or a function result.
                    result.ResolvedLocally = false;

                    break;
                }
            }


            //Reserv a new stack position if no previous position was used.
            if (stackPos.HasValue == false)
                stackPos = this.Context.ReservStackVar();


            if (result.ResolvedLocally == false)
            {
                //Release the stack of the rest of the parameters because it is not needed anymore because the stack was
                //used on previous operation.
                for (int j = i; j < fullLen; j++)
                {
                    p = ps[j];

                    if (p is FunctionResult)
                    {
                        FunctionResult funcResult = (FunctionResult)p;

                        if (funcResult.StackPosition != stackPos.Value)
                            this.Context.ReleaseStackVar(funcResult.StackPosition);
                    }
                }
            }


            if (result.ResolvedLocally == false)
            {
                //int len = fullLen - 1;

                for (i = 0; i < fullLen; i++)
                {
                    p = ps[i];

                    if (!(p is IStackValue))
                        bytesCode.Add(Convert.ToByte(p));
                    else
                        bytesCode.Add(((IStackValue)p).StackPosition);


                    //if (bytesCode.Count == bytesCodeMaxParams)
                    //{
                    //    bytesCode.Add(stackPos.Value);

                    //    operation.BytesCode.Add(bytesCode.ToArray());

                    //    bytesCode = new List<byte> { opcode, stackPos.Value, };
                    //}
                }



                //p = ps[len];

                //if (!(p is IStackValue))
                //    bytesCode.AddRange(new byte[] { Convert.ToByte(p), stackPos.Value });
                //else
                //    bytesCode.AddRange(new byte[] { ((IStackValue)p).StackPosition, stackPos.Value });

                //operation.BytesCode.Add(bytesCode.ToArray());


                bytesCode.Add(stackPos.Value);

                operation.BytesCode.Add(bytesCode.ToArray());
            }


            result.StackPosition = stackPos.Value;

            //this.Context.Operations.Add(operation);
            return result;
        }

        #endregion
    }
}
