/// <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 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);
        }