Пример #1
0
        /// <summary>
        /// Parse un block évaluable afin de retourner un IGettable.
        /// </summary>
        /// <param name="block"></param>
        /// <returns></returns>
        static IGettable ParseEvaluableBlock(EvaluableGroupToken block, GlobalContext mainContext)
        {
            EvaluableBlockExpression expr = new EvaluableBlockExpression();

            expr.Function = ParseFunction(block, mainContext);
            expr.Name     = block.Name;
            return(expr);
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }