Esempio n. 1
0
        /// <summary>
        /// Retourne la fonction statique pour un type donné dont le nom est passé en paramètre.
        /// </summary>
        /// <param name="functionName"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public Language.Function GetStaticFunction(Language.ClankTypeInstance instancedType, string functionName, List <Language.Evaluable> args, Context context)
        {
            // Obtient le nom complet de la fonction (avec les args).
            Language.ClankType owner    = instancedType.BaseType;
            string             fullName = owner.GetFullName() + "." + functionName + Language.Evaluable.GetArgTypesString(args);

            var instanciatedOverloads = InstanciatedFunc(instancedType);

            if (instanciatedOverloads.ContainsKey(fullName))
            {
                Language.Function func = instanciatedOverloads[fullName];
                // Vérification : la fonction est-elle statique ?
                if (!func.IsStatic)
                {
                    throw new SemanticError("La fonction " + functionName + " n'est pas une méthode statique de " + owner.GetFullName() + ".");
                }
                return(instanciatedOverloads[fullName]);
            }
            return(null);
        }
Esempio n. 2
0
        /// <summary>
        /// Retourne le constructeur (instancié) pour un type donné.
        /// </summary>
        public Language.Function GetConstructor(Language.ClankType owner, Language.ClankTypeInstance inst, List <Language.Evaluable> args, Context context)
        {
            string fullName            = owner.GetFullName() + "." + Language.SemanticConstants.New + Language.Evaluable.GetArgTypesString(args);
            var    instanciedOverloads = InstanciatedFunc(inst);

            if (instanciedOverloads.ContainsKey(fullName))
            {
                Language.Function func = instanciedOverloads[fullName];

                // Vérification : la fonction est-elle bien marquée comme constructeur ?
                if (!func.IsConstructor)
                {
                    throw new SemanticError("La fonction " + Language.SemanticConstants.New + " n'est pas un constructeur de " + owner.GetFullName() + ".");
                }
                return(func.Instanciate(inst.GenericArguments));
            }

            if (args.Count != 0)
            {
                throw new SemanticError("Aucun constructeur de '" + owner.GetFullName() + "' ne matche les arguments de type : " +
                                        Language.Evaluable.GetArgTypesString(args) + ". Candidats possibles : " + GetCandidatesStr(inst, Language.SemanticConstants.New));
            }

            // Si le constructeur n'existe pas, on crée le constructeur par défaut.
            Language.Function cons = new Language.Function()
            {
                Modifiers = new List <string>()
                {
                    Language.SemanticConstants.Public, Language.SemanticConstants.Constructor
                },
                ReturnType = inst,
                Arguments  = new List <Language.FunctionArgument>(),
                Code       = new List <Language.Instruction>(),
                Owner      = owner,
                Type       = inst,
                Name       = Language.SemanticConstants.New
            };
            return(cons);
        }
Esempio n. 3
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]);
            }
        }
Esempio n. 4
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;
                    }
                }
            }
        }