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