Пример #1
0
 /// <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);
     }
 }
Пример #2
0
        /// <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");
            }
        }
Пример #3
0
        /// <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");
        }
Пример #4
0
        /// <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();
        }