/// <summary>
 /// Parse une expression quelconque contenue dans un jeton,
 /// retournant un IGettable.
 /// </summary>
 /// <param name="token">
 /// Le jeton peut être un jeton contenant une liste de jetons :
 ///     - OperandTokens
 ///     - OperandOperatorGroup
 ///     - ParenthesisGroup
 /// </param>
 /// <returns></returns>
 static IGettable ParseExpression(Token token, GlobalContext mainContext)
 {
     if (token.Type == TokenType.OperandTokens)
     {
         TokenList tokens = ((OperandToken)token).Tokens;
         if (tokens.Count == 1 && tokens.First().Type == TokenType.ExpressionGroup)
         {
             return(ParseExpressionGroup((ExpressionGroupToken)tokens.First(), mainContext));
         }
         return(ParseSubExpression(tokens, mainContext));
     }
     else if (token.Type == TokenType.ExpressionGroup)
     {
         return(ParseExpressionGroup((ExpressionGroupToken)token, mainContext));
     }
     else if (token.Type == TokenType.ParenthesisGroup)
     {
         return(ParseExpression(new OperandToken(((ParenthesisGroupToken)token).Tokens), mainContext));
     }
     else if (token.Type == TokenType.EvaluableBlock)
     {
         return(ParseEvaluableBlock((EvaluableGroupToken)token, mainContext));
     }
     else
     {
         throw new Exception("Invalid token in expression"); // return Project.RpgGameRessources.ToAssetNamenew TokenList() { token }, mainContext);
     }
 }
        /// <summary>
        /// Parse une liste de jetons et retourne un block.
        /// Cette version ajoute automatiquement certains namespaces
        /// et assemblies au contexte principal avant d'évaluer le code.
        /// </summary>
        public static Block ParseBlock(TokenList tokens)
        {
            GlobalContext mainContext = new GlobalContext();

            // Namespaces de base
            mainContext.LoadedNamespaces.Add("");
            mainContext.LoadedNamespaces.Add("System");
            mainContext.LoadedNamespaces.Add("System.Text");
            mainContext.LoadedNamespaces.Add("System.Collections.Generic");
            mainContext.LoadedNamespaces.Add("Interpreter");
            // Assemblies de base
            mainContext.LoadedAssemblies = new Dictionary <string, Assembly>();
            mainContext.LoadedAssemblies.Add("mscorlib", Assembly.GetAssembly(typeof(char)));
            mainContext.LoadedAssemblies.Add("local", Assembly.GetExecutingAssembly());

            return(ParseBlock(tokens, mainContext));
        }
        /// <summary>
        /// Parse une instruction if suivi de ses éventuels blocks else et elsif.
        /// </summary>
        public static Instruction ParseIfStatement(TokenList tokens, GlobalContext mainContext)
        {
            // Parse le if
            // On a a coup sûr : if + operand + block
            IfStatement      statement    = new IfStatement();
            bool             nextIsElse   = false;
            int              tokenId      = 0;
            ConditionalBlock currentBlock = null;

            foreach (Token tok in tokens)
            {
                if (nextIsElse)
                {
                    statement.ElseBlock = ParseBlock(((BlockGroupToken)tok).Tokens, mainContext);;
                }
                else
                {
                    if (tokenId % 3 == 0) // if, else, elsif
                    {
                        currentBlock = new ConditionalBlock();
                        // Si le prochain jeton statement est un jeton else, alors on
                        // prévient que c'est le cas pour la boucle suivante.
                        if (((InfoToken)tok).Content == "else")
                        {
                            nextIsElse = true;
                        }
                    }
                    else if (tokenId % 3 == 1) // operand
                    {
                        currentBlock.Condition = ParseExpression((OperandToken)tok, mainContext);
                    }
                    else if (tokenId % 3 == 2) // block
                    {
                        currentBlock.Block = ParseBlock(((BlockGroupToken)tok).Tokens, mainContext);
                        statement.Blocks.Add(currentBlock);
                    }
                }
                tokenId++;
            }
            return(statement);
        }
        /// <summary>
        /// Parse une fonction dans un EvaluableGroupToken.
        /// Retourne uniquement la fonction.
        /// </summary>
        static Function ParseFunction(EvaluableGroupToken token, GlobalContext mainContext)
        {
            TokenList nameTokens = token.ArgumentList.Tokens;

            // Ici on parcours les jetons de exprToken (qui doit être un OperandToken)
            // afin de trouver les noms des arguments.

            // Liste contenant les noms des arguments
            List <string> argsNamesLists = new List <string>();

            // Indique si le prochain jeton doit être une virgule
            bool needComa = false;

            foreach (Token tok in nameTokens)
            {
                if (needComa && tok.Type != TokenType.Separator)
                {
                    throw new Exception("Expected ',' token in function declaration");
                }
                else
                {
                    needComa = false;
                }
                // Si c'est un nom :
                if (tok.Type == TokenType.OperandTokens && ((OperandToken)tok).Tokens.First().Type == TokenType.Noun)
                {
                    argsNamesLists.Add(((InfoToken)((OperandToken)tok).Tokens.First()).Content);
                    needComa = true;
                }
            }
            // Setup de la déclaration de fonction.
            Function fun = new Function();

            fun.ArgumentNames   = argsNamesLists;
            fun.Body            = ParseBlock(token.Block.Tokens, mainContext);
            fun.Modifiers       = ParseEvaluableBlockModifier(token.Modifiers);
            fun.PrimaryModifier = ParsePrimaryEvaluableBlockModifier(token.PrimaryModifier);
            return(fun);
        }
        /// <summary>
        /// Parse un Statement suivi de son block.
        /// En général, on obtient :
        /// Statement + Operand + BlockGroup.
        /// Le statement if pouvant être composé différemment (avec else et elsif), il n'est pas traité
        /// dans cette fonction.
        /// </summary>
        /// <param name="tokens"></param>
        /// <returns></returns>
        public static Instruction ParseBlockStatement(TokenList tokens, GlobalContext mainContext)
        {
            // Patch
            if (tokens.Count == 4 && tokens.First().Type == TokenType.Statement)
            {
                PatchInstruction patchInstruction = new PatchInstruction();

                InfoToken itoken = (InfoToken)tokens.First();
                if (itoken.Content != "patch")
                {
                    throw new Exception("Invalid statement format");
                }
                patchInstruction.FuncName = ((InfoToken)((OperandToken)tokens[1]).Tokens[0]).Content;
                InfoToken keyToken = (InfoToken)((OperandToken)(((PrefixedOperatorToken)tokens[2]).Operand)).Tokens.First();
                patchInstruction.Key          = keyToken.Content;
                patchInstruction.Instructions = ParseBlock(((BlockGroupToken)tokens[3]).Tokens).Instructions;
                return(patchInstruction);
            }

            if (tokens.Count != 3)
            {
                throw new Exception("Invalid instruction format.");
            }

            // On récupère les jetons.
            InfoToken       statementToken = tokens[0] as InfoToken;
            Token           exprToken      = tokens[1];
            BlockGroupToken blockToken     = tokens[2] as BlockGroupToken;

            if (statementToken == null || blockToken == null || statementToken.Type != TokenType.Statement)
            {
                throw new Exception("Invalid instruction format.");
            }

            Block block = ParseBlock(blockToken.Tokens, mainContext);

            switch (statementToken.Content)
            {
            case "return":
                throw new Exception();

            case "function":
                throw new Exception();

                /*TokenList exprTokens = ((OperandToken)exprToken).Tokens;
                 * FunctionDeclarationInstruction declaration = new FunctionDeclarationInstruction();
                 * TokenList nameTokens = ((ParenthesisGroupToken)exprTokens[1]).Tokens;
                 *
                 * // Ici on parcours les jetons de exprToken (qui doit être un OperandToken)
                 * // afin de trouver les noms des arguments.
                 *
                 * // Liste contenant les noms des arguments
                 * List<string> argsNamesLists = new List<string>();
                 * string funName = ((InfoToken)(exprTokens[0])).Content;
                 *
                 * // Indique si le prochain jeton doit être une virgule
                 * bool needComa = false;
                 * foreach (Token tok in nameTokens)
                 * {
                 *  if (needComa && tok.Type != TokenType.Separator)
                 *      throw new Exception("Expected ',' token in function declaration");
                 *  else
                 *      needComa = false;
                 *  // Si c'est un nom :
                 *  if (tok.Type == TokenType.OperandTokens && ((OperandToken)tok).Tokens.First().Type == TokenType.Noun)
                 *  {
                 *      argsNamesLists.Add(((InfoToken)((OperandToken)tok).Tokens.First()).Content);
                 *      needComa = true;
                 *  }
                 * }
                 * // Setup de la déclaration de fonction.
                 * declaration.Function = new Function();
                 * declaration.Function.ArgumentNames = argsNamesLists;
                 * declaration.Function.Body = block;
                 * declaration.FunctionName = funName;
                 *
                 * return declaration;*/
                break;

            case "while":
                IGettable expr = ParseExpression(exprToken, mainContext);
                block = ParseBlock(blockToken.Tokens, mainContext);
                WhileStatement statement = new WhileStatement();
                statement.Block     = block;
                statement.Condition = expr;
                return(statement);

            case "for":
                // Dans le cas d'une boucle for, expr est une opérande, contenant
                // une instruction, une expression, et une autre instruction.
                // (bizarre, certes)
                TokenList initializationInstruction = new TokenList();
                TokenList stepInstruction           = new TokenList();
                TokenList conditionExpr             = new TokenList();
                int       step = 0;
                foreach (Token tok in ((OperandToken)exprToken).Tokens)
                {
                    if (tok.Type == TokenType.EndOfInstruction)
                    {
                        step++;
                    }
                    else
                    {
                        switch (step)
                        {
                        case 0:
                            initializationInstruction.Add(tok);
                            break;

                        case 1:
                            conditionExpr.Add(tok);
                            break;

                        case 2:
                            stepInstruction.Add(tok);
                            break;
                        }
                    }
                }
                // On vérifie qu'on ait bien le bon nombre.
                if (step != 2)
                {
                    throw new Exception("Incorrect for statement.");
                }

                // On crée et on retourne le for.
                ForStatement forStatement = new ForStatement();
                forStatement.Initialisation = ParseInstruction(initializationInstruction, mainContext);
                forStatement.Condition      = ParseExpression(new OperandToken(conditionExpr), mainContext);
                forStatement.Update         = ParseInstruction(stepInstruction, mainContext);
                forStatement.Block          = block;

                return(forStatement);

            default:
                throw new NotImplementedException("Not implemented statement");
            }
        }
        /// <summary>
        /// Parse une intruction basique : appel de méthode ou affectation.
        /// La liste doit comprendre un seul jeton et pas de ;
        /// </summary>
        /// <returns></returns>
        static Instruction ParseInstruction(TokenList tokens, GlobalContext mainContext)
        {
            // Traitement spécial si return.
            if ((tokens.First().Type == TokenType.Statement))
            {
                if (tokens.Count == 2)
                {
                    InfoToken firstToken = (InfoToken)tokens[0];
                    switch (firstToken.Content)
                    {
                    case "return":
                        ReturnInstruction returnInst = new ReturnInstruction();
                        returnInst.Expression = ParseExpression(tokens[1], mainContext);
                        return(returnInst);

                    case "patchkey":
                        PatchkeyInstruction patchkeyInst = new PatchkeyInstruction();
                        patchkeyInst.Key = ((InfoToken)((OperandToken)tokens[1]).Tokens.First()).Content;
                        return(patchkeyInst);

                    default:
                        throw new Exception("Unexpected instruction");
                    }
                }
                else if (tokens.Count == 1)
                {
                    return(new ReturnInstruction());
                }
                else
                {
                    throw new Exception("Invalid 'return' expression");
                }
            }

            if (tokens.Count != 1)
            {
                // TODO : traiter les using, etc...
                throw new Exception("Unexpected token list");
            }
            Token token = tokens.First();

            // On commence les deux types d'instructions habituels.
            if (token.Type == TokenType.ExpressionGroup)
            {
                // OperandGroup + ";" : c'est une affectation, s'il n'y a pas de signe 'égal' dedans,
                // bah c'est rien du tout.
                ExpressionGroupToken   tok = (ExpressionGroupToken)token;
                AffectationInstruction ins = new AffectationInstruction();

                List <string> validTokens = new List <string>()
                {
                    "=", "+=", "-=",
                    "/=", "*="
                };

                // Si on a pas de "=", on a une expression.
                if (!validTokens.Contains(((InfoToken)tok.Operator).Content))
                {
                    throw new Exception("An expression can't be used as instruction");
                }

                ins.LeftMember = ParseSubExpression(((OperandToken)tok.Operand1).Tokens, mainContext);
                switch (((InfoToken)tok.Operator).Content)
                {
                case "=":
                    ins.RightMember = ParseExpression(tok.Operand2, mainContext);
                    break;

                case "+=":
                case "-=":
                case "/=":
                case "*=":
                    string   opString = ((InfoToken)tok.Operator).Content.Remove(1);
                    Operator op       = Operators.Mapping[opString];
                    ins.RightMember = new ExpressionGroup((IGettable)ins.LeftMember, op,
                                                          ParseExpression(tok.Operand2, mainContext));
                    break;

                default:
                    throw new Exception();
                }
                //ParseOperand((OperandToken)tok.Operand2);
                return(ins);
            }
            else if (token.Type == TokenType.OperandTokens)
            {
                TokenList internalTokens = ((TokenContainer)token).Tokens;
                Token     first          = internalTokens.First();

                // Instructions pré-faites.
                if (first.Type == TokenType.Noun)
                {
                    InfoToken itoken = (InfoToken)first;
                    switch (itoken.Content)
                    {
                    case "using":
                        if (internalTokens.Count != 2 || internalTokens[1].Type != TokenType.String)
                        {
                            throw new Exception("Invalid using instruction");
                        }
                        InfoToken itoken2 = (InfoToken)internalTokens[1];
                        mainContext.LoadedNamespaces.Add(itoken2.Content);
                        return(new UseNamespaceInstruction(itoken2.Content));

                    case "include":
                        if (internalTokens.Count != 2 || internalTokens[1].Type != TokenType.String)
                        {
                            throw new Exception("Invalid using instruction");
                        }
                        InfoToken itoken3 = (InfoToken)internalTokens[1];
                        mainContext.LoadedAssemblies.Add(itoken3.Content, Assembly.LoadWithPartialName(itoken3.Content));
                        return(new LoadAssemblyInstruction(itoken3.Content));
                    }
                }

                // C'est un appel de méthode.
                return(new MethodCallInstruction(ParseSubExpression(internalTokens, mainContext)));
            }
            throw new Exception("Uncorrect instruction");
        }
        /// <summary>
        /// Parse une partie de sous expression.
        /// Ex : machin(haha, truc), 1, truc...
        /// TODO : support indexation et génériques.
        /// </summary>
        /// <param name="tokens">
        /// Les jetons acceptés :
        ///     - Une liste d'un jeton pouvant être : Number, String => Constante
        ///                 OperandTokens, OperandOperatorGroup, ParenthesisGroup. => rééval des jetons sous-jacents.
        ///     - Une liste de jetons commençant par new, avec un Noun et un ParenthesisGroup
        ///     - Une liste d'un jeton Noun. (=> variable)
        ///     - Une liste comprenant un jeton Noun et un jeton ParenthesisGroup (=> appel de méthode).
        /// </param>
        /// <param name="part"></param>
        /// <returns></returns>
        static SubExpressionPart ParseSubExpressionPart(TokenList tokens, GlobalContext mainContext)
        {
            // Là on a le choix : string, nombre.
            if (tokens.Count == 1 && tokens.First().Type != TokenType.Noun)
            {
                Token first = tokens.First();
                if (first.Type == TokenType.Number)
                {
                    InfoToken token = (InfoToken)first;
                    return(new SubExpressionPart(token.Content, SubExpressionPart.ExpTypes.ConstantObject));
                }
                else if (first.Type == TokenType.String)
                {
                    InfoToken token = (InfoToken)first;
                    return(new SubExpressionPart(token.Content, SubExpressionPart.ExpTypes.ConstantObject));
                }
                else if (first.Type == TokenType.Bool)
                {
                    InfoToken token = (InfoToken)first;
                    return(new SubExpressionPart(token.Content, SubExpressionPart.ExpTypes.ConstantObject));
                }
                else if (first.Type == TokenType.OperandTokens)
                {
                    return(ParseSubExpressionPart(((OperandToken)first).Tokens, mainContext));
                }
                else if (first.Type == TokenType.ExpressionGroup)
                {
                    return(new SubExpressionPart(ParseExpressionGroup((ExpressionGroupToken)first, mainContext)));
                }
                else if (first.Type == TokenType.ParenthesisGroup)
                {
                    return(ParseSubExpressionPart(((ParenthesisGroupToken)first).Tokens, mainContext));
                }
                else
                {
                    throw new Exception("Invalid token in operand-token");
                }
            }
            else if (tokens.First().Type == TokenType.New)
            {
                // Création d'une instance.
                SubExpressionPart part = new SubExpressionPart("", SubExpressionPart.ExpTypes.NewObject);
                // Contiendra le nom du type, et donc le nom de la SubExpressionPart.
                StringBuilder typename = new StringBuilder();
                // Etape 1 : on parse tous les jetons constituant le nom du type.
                int index = 1;
                foreach (Token token in tokens)
                {
                    if (token == tokens.First())
                    {
                        continue;
                    }

                    if (token.Type == TokenType.Noun)
                    {
                        InfoToken info = (InfoToken)token;
                        typename.Append(info.Content);
                    }
                    else if (token.Type == TokenType.Dot)
                    {
                        typename.Append('.');
                    }
                    else if (token.Type == TokenType.ParenthesisGroup ||
                             token.Type == TokenType.IndexingParametersGroup ||
                             token.Type == TokenType.GenericParametersGroup)
                    {
                        // On arrête si on tombe sur un groupe de parenthèses ou autre.
                        break;
                    }
                    else
                    {
                        throw new Exception("Unexpected token in new expression : " + token.ToString());
                    }
                    index++;
                }
                part.Name = typename.ToString();

                // Etape 2 : on ajoute tous les groupes d'arguments.
                List <IGettable>         arguments         = new List <IGettable>();
                List <List <IGettable> > indexingArguments = new List <List <IGettable> >();
                List <IGettable>         genericArguments  = new List <IGettable>();
                for (int i = index; i < tokens.Count; i++)
                {
                    Token tok = tokens[i];
                    switch (tok.Type)
                    {
                    case TokenType.ParenthesisGroup:
                        arguments = ParseArgExpression(((TokenContainer)tok).Tokens, mainContext);
                        break;

                    case TokenType.GenericParametersGroup:
                        genericArguments = ParseArgExpression(((TokenContainer)tok).Tokens, mainContext);
                        break;

                    case TokenType.IndexingParametersGroup:
                        indexingArguments.Add(ParseArgExpression(((TokenContainer)tok).Tokens, mainContext));
                        break;

                    default:
                        throw new Exception("Unexpected token in new expression : " + tok.ToString());
                    }
                }
                part.IndexingParameters = indexingArguments;
                part.GenericParameters  = genericArguments;
                part.Parameters         = arguments;
                return(part);
            }
            else
            {
                // Variable, méthode.
                // Si parenthèses : méthode et extraire params, sinon variable ou nom de type.
                if (tokens.First().Type != TokenType.Noun)
                {
                    throw new Exception("Invalid token type in SubExpressionPart");
                }

                // Nom du membre.
                string memberName = ((InfoToken)tokens.First()).Content;

                bool hasArguments = false;

                List <IGettable>         arguments         = new List <IGettable>();
                List <List <IGettable> > indexingArguments = new List <List <IGettable> >();
                List <IGettable>         genericArguments  = new List <IGettable>();
                bool first = true;
                foreach (Token token in tokens)
                {
                    if (first)
                    {
                        first = false; continue;
                    }
                    switch (token.Type)
                    {
                    case TokenType.ParenthesisGroup:
                        hasArguments = true;
                        arguments    = ParseArgExpression(((TokenContainer)token).Tokens, mainContext);
                        break;

                    case TokenType.GenericParametersGroup:
                        genericArguments = ParseArgExpression(((TokenContainer)token).Tokens, mainContext);
                        break;

                    case TokenType.IndexingParametersGroup:
                        indexingArguments.Add(ParseArgExpression(((TokenContainer)token).Tokens, mainContext));
                        break;

                    default:
                        throw new Exception("Unexpected token in sub expression");
                    }
                }
                // Type de la sous expression.
                SubExpressionPart.ExpTypes subExprPartType = hasArguments ? SubExpressionPart.ExpTypes.Method : SubExpressionPart.ExpTypes.Variable;
                SubExpressionPart          part            = new SubExpressionPart(memberName, subExprPartType);
                part.Parameters         = arguments;
                part.IndexingParameters = indexingArguments;
                part.GenericParameters  = genericArguments;

                return(part);
            }
            throw new Exception();
        }
        /// <summary>
        /// Parse une liste de jetons et retourne un block d'instruction.
        /// </summary>
        public static Block ParseBlock(TokenList tokens, GlobalContext mainContext)
        {
            Block mainBlock = new Block(mainContext);

            mainBlock.Instructions = new List <ExpressionTree.Instructions.Instruction>();

            // Détermine si on a commencé à parser un block if.
            bool parseIfStarted = false;

            // On commence le parsing
            TokenList tokenStack = new TokenList();

            tokens.Add(new Token(TokenType.EndOfBlock));
            foreach (Token token in tokens)
            {
                if (parseIfStarted)
                {
                    if (token.Type == TokenType.BlockGroup)
                    {
                        tokenStack.Add(token);
                        // Si le dernier statement était un else, alors on termine sur ce jeton.
                        if (tokenStack.Last().Type == TokenType.Statement && ((InfoToken)token).Content == "else")
                        {
                            mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext));
                            tokenStack.Clear();
                            parseIfStarted = false;
                        }
                        continue;
                    }
                    else if (token.Type == TokenType.OperandTokens)
                    {
                        // Si on a un statement avant ça (if ou elsif en particulier)
                        if (tokenStack.Last().Type == TokenType.Statement)
                        {
                            // On ne prend une opérande qu'après un if ou elsif
                            InfoToken last = (InfoToken)tokenStack.Last();
                            if (last.Content == "elsif" || last.Content == "if")
                            {
                                tokenStack.Add(token);
                                continue;
                            }
                        }
                        // Si ce n'est pas le cas, c'est que cette opérande vient après le block
                        // if ou elsif, donc on finit.
                        mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext));
                        tokenStack.Clear();
                        parseIfStarted = false;
                    }
                    // Si c'est un elsif : on prend le prochain block
                    else if (token.Type == TokenType.Statement)
                    {
                        InfoToken iToken = (InfoToken)token;
                        if (iToken.Content == "elsif")
                        {
                            tokenStack.Add(iToken);
                            continue;
                        }
                        else if (iToken.Content == "else")
                        {
                            tokenStack.Add(iToken);
                            continue;
                        }
                        else
                        {
                            // c'est un statement qui n'a rien avoir avec ça, donc on termine.
                            mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext));
                            tokenStack.Clear();
                            parseIfStarted = false;
                        }
                    }
                    else
                    {
                        mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext));
                        tokenStack.Clear();
                        parseIfStarted = false;
                    }
                }

                // Les possibilités de patterns :
                // OperandGroup + ";" : c'est une affectation, s'il n'y a pas de signe 'égal' dedans,
                // bah c'est rien du tout.
                // Une Opérande + ";" : c'est soit une déclaration de variable (en deux temps donc),
                //                      soit un appel de fonction.
                // Un statement + une opérande + début de block : statement bien entendu.
                // Stratégie : on stack les jetons jusqu'à rencontrer un début de block ou
                // un point virgule. On analyse ensuite ce que l'on trouve :D
                if (token.Type == TokenType.EndOfInstruction)
                {
                    mainBlock.Instructions.Add(ParseInstruction(tokenStack, mainContext));
                    tokenStack.Clear();
                }
                else if (token.Type == TokenType.EvaluableBlock && tokenStack.Count == 0)
                {
                    // Si la pile de jetons est vide, on est en début d'instruction, on a une déclaration
                    // de fonction.
                    // Sinon, on ajoute seulement le jeton à la liste de jetons (dans le else).
                    EvaluableGroupToken            blockToken = (EvaluableGroupToken)token;
                    FunctionDeclarationInstruction ins        = new FunctionDeclarationInstruction();
                    ins.Function     = ParseFunction(blockToken, mainContext);
                    ins.FunctionName = blockToken.Name;
                    mainBlock.Instructions.Add(ins);
                    tokenStack.Clear();
                }
                else if (token.Type == TokenType.Statement && ((InfoToken)token).Content == "if")
                {
                    if (tokenStack.Count != 0)
                    {
                        throw new Exception("Syntax error : unexpected token(s) before 'if' statement");
                    }

                    tokenStack.Add(token);
                    parseIfStarted = true;
                }
                else if (token.Type == TokenType.BlockGroup) // fin de block.
                {
                    tokenStack.Add(token);
                    mainBlock.Instructions.Add(ParseBlockStatement(tokenStack, mainContext));
                    tokenStack.Clear();
                }
                else
                {
                    tokenStack.Add(token);
                }
            }
            return(mainBlock);
        }
        /// <summary>
        /// Parse une sous-expression de la forme :
        /// 5.machin(haha, truc).bidule.chose[6].truc(hoho)
        /// <param name="tokens">
        /// Liste de jetons, en particulier :
        ///     - Noun, Number
        ///     - ParenthesisGroup, OperandGroup
        ///     - Dot
        /// </param>
        /// </summary>
        static SubExpression ParseSubExpression(TokenList tokens, GlobalContext mainContext)
        {
            tokens = tokens.Copy();
            SubExpression exp = new SubExpression();

            exp.Parts = new List <SubExpressionPart>();
            // Si on a un new, on ne vérifie pas qu'on ait un nom de type de cette manière :
            // on parse la SubExpression (donc new <Nom.Du.Type> () ) directement.
            if (tokens.First().Type != TokenType.New)
            {
                // Déja on vérifie qu'il y ait un nom de type avant, pour voir
                // si on appelle une méthode statique.
                bool containsTypeName = false;

                // Permet de savoir à quel jeton démarrer lors du prochain parsing :
                // on skip les jetons correspondant au type.
                int           lastTypeTokenId = 0;
                int           id       = 0;
                string        lastName = null;
                StringBuilder name     = new StringBuilder();
                foreach (Token token in tokens)
                {
                    id++;
                    if (token.Type == TokenType.Dot)
                    {
                        name.Append(".");
                    }
                    else if (token.Type == TokenType.Noun)
                    {
                        name.Append(((InfoToken)token).Content);
                    }
                    else if (token.Type == TokenType.GenericParametersGroup)
                    {
                        name.Append("`" + ((TokenContainer)token).Tokens.Count);
                    }
                    else if (token.Type == TokenType.ParenthesisGroup)
                    {
                        break;
                    }


                    bool isType = ReflectionUtils.IsTypeName(mainContext.LoadedAssemblies, mainContext.LoadedNamespaces, name.ToString());
                    if (isType)
                    {
                        lastTypeTokenId  = id;
                        containsTypeName = true;
                        lastName         = name.ToString();
                        // on finit pas au cas où on ait un NestedType.
                    }
                }
                // On skip les token du type.
                // TODO : ça bugue s'il n'y a pas de points.
                if (containsTypeName)
                {
                    SubExpressionPart part = new SubExpressionPart(lastName, SubExpressionPart.ExpTypes.ConstantTypeName);
                    exp.Parts.Add(part);
                    // On enlève ce nom de type pour le prochain parsing :
                    if (tokens.Count >= lastTypeTokenId + 1)
                    {
                        tokens.RemoveRange(0, lastTypeTokenId + 1);
                    }
                    else
                    {
                        // l'expression est déja terminée.
                        return(exp);
                    }
                }
            }
            else // new
            {
                // Dans ce cas, la sub expression part du type s'étend jusqu'à la prochaine
                // parenthèse.

                // Liste de jetons représentant l'expression new
                TokenList newExprList = new TokenList();
                bool      isOK        = false;
                // On parcours la liste de jetons originale en
                // supprimant les objets que l'on va parser.
                while (true && tokens.Count != 0)
                {
                    if (tokens[0].Type == TokenType.ParenthesisGroup)
                    {
                        newExprList.Add(tokens[0]);
                        tokens.RemoveAt(0);
                        isOK = true;
                        break;
                    }
                    newExprList.Add(tokens[0]);
                    tokens.RemoveAt(0);
                }
                exp.Parts.Add(ParseSubExpressionPart(newExprList, mainContext));
            }

            TokenList tempTokens = new TokenList();

            foreach (Token token in tokens)
            {
                if (token.Type != TokenType.Dot)
                {
                    tempTokens.Add(token);
                }
                else if (tempTokens.Count != 0)
                {
                    SubExpressionPart part = ParseSubExpressionPart(tempTokens, mainContext);
                    tempTokens.Clear();
                    exp.Parts.Add(part);
                }
            }
            // Car à la fin il n'y a pas de point.
            if (tempTokens.Count != 0)
            {
                SubExpressionPart part = ParseSubExpressionPart(tempTokens, mainContext);
                tempTokens.Clear();
                exp.Parts.Add(part);
            }

            return(exp);
        }