#region License
/* **********************************************************************************
 * Copyright (c) Roman Ivantsov
 * This source code is subject to terms and conditions of the MIT License
 * for Irony. A copy of the license can be found in the License.txt file
 * at the root of this distribution. 
 * By using this source code in any fashion, you are agreeing to be bound by the terms of the 
 * MIT License.
 * You must not remove this notice from this software.
 * **********************************************************************************/
#endregion

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

using Irony.Ast;
using Irony.Parsing;

namespace Irony.Interpreter.Ast
{

    public class WhileNode : AstNode
    {
        object result = null;
        private AstNode CondotionAst;
        private AstNode LoopBodyAst;


        public override void Init(AstContext context , ParseTreeNode treeNode)
        {
            base.Init(context , treeNode);
            //treenodeのchildnodeが２つあるとき、返値用のASTノードを追加
            if (treeNode.ChildNodes != null && treeNode.ChildNodes.Count >= 2)
            {
                //仮変数＝初期値ノードをASTに追加
                CondotionAst = AddChild(NodeUseType.ValueReadWrite , "Condition" , treeNode.ChildNodes[0]);

                //ループボディをASTに追加　　　　.CallTarget？？
                LoopBodyAst = AddChild(NodeUseType.Unknown , "LoopBody" , treeNode.ChildNodes[1]);
            }
            else
            {
                this.ErrorAnchor = Span.Location;
            }

            AsString = "while";
        }

        object LockObject = new object();
        protected override object DoEvaluate(ScriptThread thread)
        {
            bool Istrue = false;

            //return、break、Continueを受け取る
            resultWithReturnType resWithRet = null;


            thread.CurrentNode = this;  //standard prolog



            //ループ処理
            while (thread.Runtime.IsTrue( CondotionAst.Evaluate(thread) ))
            {
                //ブロック実施
                result = LoopBodyAst.Evaluate(thread);

                //Break,Continueで途中で抜けた場合、resultWithReturnTypeが戻ってくる。
                resWithRet = result as resultWithReturnType;
                if (resWithRet != null)
                {
                    if (resWithRet.retType == ReturnType.EXIT_LOOP)
                    {
                        //１階層上に戻る
                        result = resWithRet.resultObj;
                        break;
                    }

                    if (resWithRet.retType == ReturnType.EXIT_FUNCTION)
                    {
                        //１階層上に戻るが、関数を抜けるまでフラグを立てたままにする。
                        break;
                    }

                    if (resWithRet.retType == ReturnType.CONTINUE_LOOP)
                    {
                        continue;
                    }
                }
            }

            thread.CurrentNode = Parent; //standard epilog
            return result;
        }//method
    }//class

}//namespace
