Ejemplo n.º 1
0
        /// <summary>
        /// Retourne vrai si les jetons contenus dans token matchent ce pattern.
        /// </summary>
        /// <param name="tokens"></param>
        /// <returns></returns>
        public Match MatchPattern(List <Token> tokens)
        {
            Match m = new Match()
            {
                MatchPattern = false, MatchUnits = new List <MatchUnit>()
            };

            for (int i = 0; i < tokens.Count; i++)
            {
                Token token = tokens[i];
                if (MatchPattern(token))
                {
                    m.MatchUnits.Add(new MatchUnit()
                    {
                        Identifier = this.Identifier, MatchedToken = token
                    });

                    Match nextMatch;
                    // Si répétition autorisée, on regarde si ce motif se répète.
                    if (Repeats)
                    {
                        nextMatch = MatchPattern(tokens.GetRange(i + 1, tokens.Count - i - 1));
                        if (nextMatch.MatchPattern)
                        {
                            m.MatchUnits.AddRange(nextMatch.MatchUnits);
                            m.MatchPattern = true;
                            break;
                        }
                        // Pas de répétition : on passe au suivant.
                    }

                    // Motif suivant
                    if (Next != null)
                    {
                        nextMatch = Next.MatchPattern(tokens.GetRange(i + 1, tokens.Count - i - 1));
                        if (nextMatch.MatchPattern)
                        {
                            m.MatchUnits.AddRange(nextMatch.MatchUnits);
                            m.MatchPattern = true;
                            break;
                        }
                    }
                    else
                    {
                        // Si on a fini, on veut que l'instruction ne contienne plus rien.
                        if (i == tokens.Count - 1)
                        {
                            m.MatchPattern = true;
                        }
                    }
                }
                else if (Optional && Next != null)
                {
                    return(Next.MatchPattern(tokens.GetRange(i, tokens.Count - i)));
                }
            }
            return(m);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parse le jeton pour en extraire une instance de type de base en fonction du contexte.
        /// </summary>
        public Language.ClankTypeInstance FetchInstancedType(Token token, Context context, bool containsType = false)
        {
            Language.ClankType baseType = null;
            bool isGeneric = false;
            List <Language.ClankTypeInstance> genericArguments = new List <Language.ClankTypeInstance>();

            if (token.TkType == TokenType.List)
            {
                if (token.ListTokens.Count != 1)
                {
                    throw new InvalidOperationException();
                }

                return(FetchInstancedType(token.ListTokens[0], context, containsType));
            }
            else if (token.TkType == TokenType.ArrayType)
            {
                // On crée un array avec comme param générique le type de cette array.
                baseType = Types["Array"];
                Language.ClankTypeInstance inst = FetchInstancedType(token.ArrayTypeIdentifier, context, containsType);

                if (inst == null)
                {
                    string error = "Le type " + token.ArrayTypeIdentifier.Content + " n'existe pas.";
                    if (OnLog != null)
                    {
                        OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, token.Line, token.Character, token.Source));
                    }
                    throw new SemanticError(error);
                }

                genericArguments.Add(inst);
                isGeneric = true;
            }
            else if (token.TkType == TokenType.GenericType)
            {
                if (!Types.ContainsKey(token.GenericTypeIdentifier.Content))
                {
                    // Erreur type inconnu.
                    string error = "Le type générique '" + token.GenericTypeIdentifier.Content + "' est n'existe pas.";
                    OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, token.Line, token.Character, token.Source));
                    throw new SemanticError(error);
                }
                baseType  = Types[token.GenericTypeIdentifier.Content];
                isGeneric = true;
                foreach (Token tok in token.GenericTypeArgs.ListTokens)
                {
                    Language.ClankTypeInstance inst = FetchInstancedType(tok, context, true);
                    if (inst == null)
                    {
                        string error = "Le type '" + tok.ToReadableCode() + "' n'existe pas.";
                        if (OnLog != null)
                        {
                            OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, token.Line, token.Character, token.Source));
                        }
                        throw new SemanticError(error);
                    }
                    genericArguments.Add(inst);
                }
                // Vérification : le nombre d'arguments du type générique est-il correct ?
                if (baseType.GenericArgumentNames.Count != token.GenericTypeArgs.ListTokens.Count)
                {
                    string error = "Nombre d'arguments pour le type '" + baseType.GetFullName() + "' incorrect. Attendu : " + baseType.GetFullNameAndGenericArgs() +
                                   ". Obtenu " + baseType.GetFullName() + "<" + token.GenericTypeArgs.ToReadableCode() + "> (" + token.GenericTypeArgs.ListTokens.Count + " args).";

                    if (OnLog != null)
                    {
                        OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, token.Line, token.Character, token.Source));
                    }
                }
            }
            else if (token.TkType == TokenType.Name)
            {
                if (TypeInstances.ContainsKey(token.Content))
                {
                    return(TypeInstances[token.Content]);
                }
                else
                {
                    Context c = context;
                    while (c != null)
                    {
                        string contextPrefix = c.GetContextPrefix().Trim('.') + "'";
                        if (TypeInstances.ContainsKey(contextPrefix + token.Content))
                        {
                            // Instance de type générique
                            return(TypeInstances[contextPrefix + token.Content]);
                        }
                        c = c.ParentContext;
                    }
                }

                baseType = new Language.ClankType()
                {
                    Name = token.Content
                };
                // FIXME : enlever true va créer une nouvelle instance de type basé sur un nouveau
                // type (baseType du dessus là) pas encore déclaré. -> on casse des références.
                if (!containsType || true)
                {
                    // Rien n'a été trouvé, on retourne null. (ce n'est pas un type)
                    return(null);
                }
            }

            Language.ClankTypeInstance type = new Language.ClankTypeInstance()
            {
                BaseType         = baseType,
                GenericArguments = genericArguments
            };

            string fullName = type.GetFullName();

            if (!TypeInstances.ContainsKey(fullName))
            {
                TypeInstances.Add(fullName, type);
                return(type);
            }
            else
            {
                return(TypeInstances[fullName]);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Effectue une recherche des types déclarés dans le script passé en paramètre.
        ///
        /// Seule la section "State" du script doit être passée.
        /// </summary>
        void FetchTypes(List <Token> tokens, Context context)
        {
            bool foundClass = false;
            bool isPublic   = false;
            bool foundEnum  = false;

            foreach (Token token in tokens)
            {
                if (foundClass)
                {
                    #region FoundClass
                    if (token.TkType == TokenType.NamedCodeBlock)
                    {
                        // SECU : vérifier que CodeBlockIdentifier est un Name.

                        // Crée le type de base.
                        Language.ClankType newType = new Language.ClankType()
                        {
                            Name     = token.NamedCodeBlockIdentifier.Content,
                            IsPublic = isPublic,
                            IsMacro  = context.BlockName == Language.SemanticConstants.MacroBk
                        };

                        // Crée l'instance associée.
                        Language.ClankTypeInstance newTypeInstance = new Language.ClankTypeInstance()
                        {
                            BaseType         = newType,
                            GenericArguments = new List <Language.ClankTypeInstance>(),
                        };

                        string fullname = newTypeInstance.GetFullName();
                        if (TypeInstances.ContainsKey(fullname))
                        {
                            TypeInstances[fullname] = newTypeInstance;
                        }
                        else
                        {
                            TypeInstances.Add(newTypeInstance.GetFullName(), newTypeInstance);
                        }

                        // Si le type existe déjà : on le remplace.
                        if (Types.ContainsKey(newType.Name))
                        {
                            OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, "Le type '" + newType.Name + "' est déjà défini.",
                                                           token.Line, token.Character, token.Source));
                        }

                        Types.Add(newType.Name, newType);
                    }
                    // On cherche les paramètres génériques et on en crée des instances.
                    else if (token.TkType == TokenType.NamedGenericCodeBlock)
                    {
                        List <string> genericArgsNames = new List <string>();

                        // Arguments du type générique
                        foreach (Token t in token.NamedGenericCodeBlockArgs.ListTokens)
                        {
                            if (t.ListTokens.Count != 1 && t.ChildToken.TkType != TokenType.Name)
                            {
                                throw new InvalidOperationException("Déclaration d'argument générique invalide");
                            }

                            // Identificateur du type : contient son nom.
                            genericArgsNames.Add(t.ChildToken.Content);
                        }

                        // Nouveau type générique
                        Language.ClankType newType = new Language.ClankType()
                        {
                            Name = token.NamedGenericCodeBlockNameIdentifier.Content,
                            GenericArgumentNames = genericArgsNames,
                            IsPublic             = isPublic,
                            IsMacro = context.BlockName == Language.SemanticConstants.MacroBk
                        };

                        // Override pour le type array.
                        if (newType.Name == "Array" && newType.GenericArgumentNames.Count == 1 && newType.IsMacro)
                        {
                            newType = Types[newType.Name];
                        }
                        else
                        {
                            Types.Add(newType.Name, newType);
                        }

                        // Création du contexte fils
                        Context childContext = new Context();
                        childContext.ParentContext = context;
                        childContext.Container     = newType;

                        // Création des types génériques et de leur instance.
                        string contextPrefix = childContext.GetContextPrefix().Trim('.') + "'";
                        for (int i = 0; i < genericArgsNames.Count; i++)
                        {
                            Language.GenericParameterType genericType = new Language.GenericParameterType()
                            {
                                ParamId = i,
                                Name    = genericArgsNames[i],
                                Prefix  = contextPrefix
                            };

                            Types.Add(genericType.GetFullName(), genericType);
                            TypeInstances.Add(contextPrefix + genericArgsNames[i], new Language.ClankTypeInstance()
                            {
                                BaseType = genericType,
                            });
                        }



                        // Recherche d'autres types dans les instructions.
                        FetchTypes(token.NamedGenericCodeBlockInstructions.ListTokens, childContext);
                    }
                    else
                    {
                        // throw new InvalidOperationException("Déclaration de classe attendue.");
                        continue;
                    }
                    #endregion

                    foundClass = false;
                    isPublic   = false;
                }
                else if (foundEnum)
                {
                    #region Found enum
                    if (token.TkType == TokenType.NamedCodeBlock)
                    {
                        // Crée le type de base.
                        Language.ClankType newType = new Language.ClankType()
                        {
                            Name                          = token.NamedCodeBlockIdentifier.Content,
                            IsPublic                      = isPublic,
                            IsEnum                        = true,
                            JType                         = Language.JSONType.Int,
                            SupportSerialization          = true,
                            SupportSerializationAsGeneric = true
                        };

                        // Crée l'instance associée.
                        Language.ClankTypeInstance newTypeInstance = new Language.ClankTypeInstance()
                        {
                            BaseType         = newType,
                            GenericArguments = new List <Language.ClankTypeInstance>(),
                        };

                        // Ajoute les membres de l'enum.
                        string currentName  = null;
                        int    currentValue = 0;
                        foreach (Token tk in token.NamedCodeBlockInstructions.ListTokens)
                        {
                            if (tk.TkType != TokenType.List || tk.ChildToken.TkType != TokenType.ExpressionGroup)
                            {
                                string error = "Erreur de syntaxe dans la déclaration d'enum : jeton '" + tk.ToReadableCode() + "' inattendu.";
                                OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, tk.Line, tk.Character, tk.Source));
                                throw new Tokenizers.SyntaxError(error, tk.Line, tk.Source);
                            }

                            Token expr  = tk.ChildToken;
                            Token name  = expr.Operands1.ChildToken;
                            Token value = expr.Operands2.ChildToken;
                            Token op    = expr.Operator;

                            if (name.TkType == TokenType.Name && value.TkType == TokenType.NumberLiteral && op.Content == "=")
                            {
                                currentValue = Int32.Parse(value.Content);
                                currentName  = name.Content;
                                // Erreur si doublon.
                                if (newType.EnumValues.ContainsKey(currentName))
                                {
                                    string error = "La valeur '" + currentName + "' est déjà présente dans l'énumération '" + newType.Name + "'.";
                                    OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, error, tk.Line, tk.Character, tk.Source));
                                    throw new Tokenizers.SyntaxError(error, tk.Line, tk.Source);
                                }

                                newType.EnumValues.Add(currentName, currentValue);
                            }
                        }

                        // Ajoute le type dans la table des types.
                        string fullname = newTypeInstance.GetFullName();
                        if (TypeInstances.ContainsKey(fullname))
                        {
                            TypeInstances[fullname] = newTypeInstance;
                        }
                        else
                        {
                            TypeInstances.Add(newTypeInstance.GetFullName(), newTypeInstance);
                        }

                        // Si le type existe déjà : on le remplace.
                        if (Types.ContainsKey(newType.Name))
                        {
                            OnLog(new Tools.EventLog.Entry(Tools.EventLog.EntryType.Error, "Le type énuméré'" + newType.Name + "' est déjà défini.",
                                                           token.Line, token.Character, token.Source));
                        }

                        Types.Add(newType.Name, newType);
                    }

                    #endregion

                    foundEnum = false;
                    isPublic  = false;
                }
                else // if !foundClass
                {
                    switch (token.TkType)
                    {
                    // Parsing récursif des Listes
                    case TokenType.ArgList:
                    case TokenType.CodeBlock:
                    case TokenType.List:
                    case TokenType.InstructionList:
                        FetchTypes(token.ListTokens, context);
                        break;

                    case TokenType.NamedCodeBlock:
                        context.BlockName = token.NamedCodeBlockIdentifier.Content;
                        FetchTypes(token.ListTokens, context);
                        break;

                    // Vérification du mot clef class
                    case TokenType.Name:
                        if (token.Content == Language.SemanticConstants.Class)
                        {
                            foundClass = true;
                        }
                        else if (token.Content == Language.SemanticConstants.Enum)
                        {
                            foundEnum = true;
                        }
                        else if (token.Content == Language.SemanticConstants.Public)
                        {
                            isPublic = true;
                        }
                        break;
                    }
                }
            }
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Retourne vrai si le jeton donné match avec ce bout de pattern.
 /// </summary>
 /// <param name="token"></param>
 /// <returns></returns>
 public bool MatchPattern(Token token)
 {
     return((Content == null || Content.Count == 0 || Content.Contains(token.Content)) && (TkType.Contains(token.TkType)));
 }