Esempio n. 1
0
        /// <summary>
        /// Retourne le flag modificateur correspondant au jeton modificateur donné.
        /// </summary>
        static PrimaryEvaluableBlockModifiers ParsePrimaryEvaluableBlockModifier(InfoToken token)
        {
            switch (token.Content)
            {
            case SyntaxParsing.SyntaxicParser.LAMBDA_KW:
                return(PrimaryEvaluableBlockModifiers.Lambda);

            case SyntaxParsing.SyntaxicParser.FUNCTION_KW:
                return(PrimaryEvaluableBlockModifiers.Function);
            }
            throw new Exception();
        }
Esempio n. 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");
            }
        }
Esempio n. 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");
        }
Esempio n. 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();
        }
Esempio n. 5
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);
        }