/// <summary> /// Génère un modèle abstrait représentant les classes à créer pour le serveur du projet cible. /// </summary> /// <returns></returns> public List <Language.Instruction> GenerateClientProject() { List <Language.Instruction> classes = new List <Language.Instruction>(); // Copie de la classe state Language.ClassDeclaration stateClass = State.StateClass.Copy(); stateClass.Modifiers.Add("public"); // Ajoute les enums. classes.AddRange(stateClass.Instructions.Where((Language.Instruction inst) => { return(inst is Language.EnumDeclaration); })); // Ne conserve que les fonctions. stateClass.Instructions = stateClass.Instructions.Where((Language.Instruction inst) => { // Ne garde que les fonctions. return(inst is Language.FunctionDeclaration); }).ToList(); stateClass.Comment = "Contient toutes les informations concernant l'état du serveur."; // Copie des classes state PUBLIQUES List <Language.ClassDeclaration> stateClasses = new List <Language.ClassDeclaration>(); foreach (Language.ClassDeclaration decl in State.Classes) { if (decl.Modifiers.Contains(Language.SemanticConstants.Public)) { stateClasses.Add(decl.Copy()); } } ; // Ajoute les méthodes access / write. int id = 0; foreach (Language.FunctionDeclaration method in Access.Declarations) { stateClass.Instructions.Add(new Model.Language.Macros.RemoteFunctionWrapper(method, id)); id++; } foreach (Language.FunctionDeclaration method in Write.Declarations) { stateClass.Instructions.Add(new Model.Language.Macros.RemoteFunctionWrapper(method, id)); id++; } classes.AddRange(stateClasses); classes.Add(stateClass); return(classes); }
/// <summary> /// Crée une nouvelle instance de StateContainer. /// </summary> public StateContainer() { ParsingLog = new Tools.EventLog(); StateClass = new Language.ClassDeclaration() { Name = Language.SemanticConstants.StateClass, Source = "generated" }; // new Language.ClankType() { Name = "State" }; Classes = new List <Language.ClassDeclaration>(); }
/// <summary> /// Crée et retourne une copie superficielle de cette déclaration de classe. /// </summary> /// <returns></returns> public ClassDeclaration Copy() { ClassDeclaration newClass = new ClassDeclaration(); newClass.Name = Name; newClass.Modifiers = Modifiers; newClass.GenericParameters = GenericParameters; newClass.Instructions = new List <Instruction>(); foreach (Instruction ins in Instructions) { newClass.Instructions.Add(ins); } ; newClass.ContextPrefix = ContextPrefix; newClass.Line = Line; newClass.Character = Character; newClass.Source = Source; return(newClass); }
/// <summary> /// Vérifie que la classe passée en paramètre respecte les conditions pour être marquée sérializable /// (si elle l'est). /// </summary> void PerformSerializableChecking(Language.ClassDeclaration decl, Semantic.TypeTable types) { Language.ClankType type = types.Types[decl.Name]; if (!type.SupportSerialization) { return; } bool hasError = false; string error = "La classe '" + decl.Name + "' est marquée serializable mais contient des variables non serializables : "; // Vérifie que les types des variables d'instances sont tous "serializable". foreach (var kvp in type.InstanceVariables) { string name = kvp.Key; Language.Variable variable = kvp.Value; // Si la variable a des paramètres génériqu if (variable.Type.BaseType.HasGenericParameterTypeMembers()) { /*if(!variable.Type.BaseType.SupportSerializationAsGeneric) * { * hasError = true; * error += variable.ToString() + " ne supporte pas la sérialisation en tant que param générique, "; * }*/ // On ne peut pas check maintenant, il faut connaître les params génériques. } else if (!(variable.Type.BaseType is Language.GenericParameterType)) { List <string> dummy; if (!variable.Type.DoesSupportSerialization(out dummy)) { hasError = true; error += variable.ToString() + "ne supporte pas la sérialisation, "; } } } if (hasError) { error = error.TrimEnd(',', ' '); ParsingLog.AddWarning(error, decl.Line, decl.Character, decl.Source); } }
/// <summary> /// Ajoute des déclarations à ce Container à partir d'un block Access. /// </summary> /// <param name="block"></param> void AddDeclarationsFromMacroBlock(Language.NamedBlockDeclaration block, Semantic.TypeTable table) { foreach (Language.Instruction instruction in block.Instructions) { if (instruction is Language.ClassDeclaration) { Language.ClassDeclaration classDecl = (Language.ClassDeclaration)instruction; MacroClass classMacro = new MacroClass(); // Récupération du type en language Clank.Core. Language.ClankType type = table.Types[classDecl.GetFullName()]; classMacro.Type = type; bool foundName = false; // Parse les instructions à la recherche de : // - une fonction Name qui retourne un string et qui contient des variables de type string // - d'autres fonctions qui ne contiennent que des variables de type string. foreach (Language.Instruction funcDeclInstruction in classDecl.Instructions) { Language.FunctionDeclaration funcDecl = funcDeclInstruction as Language.FunctionDeclaration; if (funcDecl != null) { if (funcDecl.Func.Name == "name") { // Nom de la classe foundName = true; classMacro.LanguageToTypeName = ParseLanguageTranslations(funcDecl); } else { // Ajout de la fonction. MacroFunction func = new MacroFunction(); func.Function = funcDecl.Func; func.LanguageToFunctionName = ParseLanguageTranslations(funcDecl); classMacro.Functions.Add(func.Function.GetFullName(), func); } } else if (funcDeclInstruction is Language.PlaceholderInstruction) { } else { ParsingLog.AddWarning("Seules les déclarations de fonctions sont autorisées dans les classes de block macro. Obtenu : " + funcDeclInstruction.GetType().Name + ".", instruction.Line, instruction.Character, instruction.Source); } } ClassDeclarations.Add(classMacro); // Erreur si pas de nom de classe trouvé : if (!foundName) { ParsingLog.AddError("Fonction 'string name()' attendue dans la déclaration de macro du type '" + type.Name + "'.", instruction.Line, instruction.Character, instruction.Source); } } else if (instruction is Language.FunctionDeclaration) { Language.FunctionDeclaration funcDecl = (Language.FunctionDeclaration)instruction; MacroFunction func = new MacroFunction(); func.Function = funcDecl.Func; func.LanguageToFunctionName = ParseLanguageTranslations(funcDecl); FunctionDeclarations.Add(func); } else { ParsingLog.AddWarning("Déclaration de classe attendue dans le block macro. Obtenu : " + instruction.GetType() + ".", instruction.Line, instruction.Character, instruction.Source); } } }
/// <summary> /// Génère un modèle abstrait représentant les classes à créer pour le serveur du projet cible. /// </summary> /// <returns></returns> public List <Language.Instruction> GenerateServerProject() { List <Language.Instruction> classes = new List <Language.Instruction>(); // Copie de la classe state Language.ClassDeclaration stateClass = State.StateClass.Copy(); stateClass.Modifiers.Add("public"); stateClass.Comment = "Contient toutes les informations concernant l'état du serveur."; // Copie des classes state List <Language.ClassDeclaration> stateClasses = new List <Language.ClassDeclaration>(); foreach (Language.ClassDeclaration decl in State.Classes) { stateClasses.Add(decl.Copy()); } ; // Ajoute les enums. classes.AddRange(stateClass.Instructions.Where((Language.Instruction inst) => { return(inst is Language.EnumDeclaration); })); // Ne conserve que les fonctions dans la classe state. stateClass.Instructions = stateClass.Instructions.Where((Language.Instruction inst) => { // Ne garde que les fonctions. return(inst is Language.FunctionDeclaration); }).ToList(); // Ajoute les méthodes access / write. foreach (Language.FunctionDeclaration method in Access.Declarations) { Language.FunctionDeclaration cpy = method.FuncCopy(); cpy.Func.Arguments.Add(new Language.FunctionArgument() { ArgType = Types.FetchInstancedType("int", new Semantic.TypeTable.Context()), ArgName = Language.SemanticConstants.ClientID }); stateClass.Instructions.Add(cpy); } foreach (Language.FunctionDeclaration method in Write.Declarations) { Language.FunctionDeclaration cpy = method.FuncCopy(); cpy.Func.Arguments.Add(new Language.FunctionArgument() { ArgType = Types.FetchInstancedType("int", new Semantic.TypeTable.Context()), ArgName = Language.SemanticConstants.ClientID }); stateClass.Instructions.Add(cpy); } // Ajoute la méthode de traitement des messages. // Le code effectif de cette méthode est créé par le générateur de code // du language cible. Language.Macros.ProcessMessageMacro processFunc = new Language.Macros.ProcessMessageMacro(Access, Write); processFunc.Comment = "Génère le code pour la fonction de traitement des messages."; stateClass.Instructions.Add(processFunc); // Classe de message //Language.ClassDeclaration messageClass = new Language.ClassDeclaration() { Name = "_Message" }; //messageClass.Instructions.Add(new Language.VariableDeclarationInstruction() { Var = new Language.Variable() { Name = "Type", Type = enumMessageTypeInstance } }); // Classes de message //List<Language.ClassDeclaration> messageClasses = new List<Language.ClassDeclaration>(); #if false // Ajout des fonctions de Write. #region Write foreach (Language.FunctionDeclaration ex in Write.Declarations) { // Membre de l'enum de message enumDecl.Members.Add("MessageType_" + ex.Func.Name); // Classe de message Language.ClankType klassType = new Language.ClankType() { Name = "Write_" + ex.Func.Name + "_Message" }; Language.ClassDeclaration klass = new Language.ClassDeclaration(); klass.Name = klassType.Name; // Création d'un constructeur. Language.Constructor cons = new Language.Constructor(); cons.Owner = klassType; // Création : // Des variables d'instance de la classe. // Des paramètres du constructeur, de l'initialisation de ces paramètres foreach (Language.FunctionArgument arg in ex.Func.Arguments) { Language.Variable argVar = new Language.Variable() { Name = "_" + arg.ArgName, Type = arg.ArgType }; // Déclaration de la variable klass.Instructions.Add(new Language.VariableDeclarationInstruction() { Var = argVar, Modifiers = new List <string>() { "public" } }); // Ajout de l'argument au constructeur. cons.Arguments.Add(arg); // Ajout de l'assignement de la variable cons.Code.Add(new Language.AffectationInstruction() { Expression = new Language.BinaryExpressionGroup() { Operand1 = argVar, Operand2 = new Language.Variable() { Name = arg.ArgName, Type = arg.ArgType }, Operator = Language.Operator.Affectation } }); } // Ajout de la nouvelle classe. klass.Instructions.Add(new Language.ConstructorDeclaration() { Func = cons }); messageClasses.Add(klass); // Déclaration de fonction dans State. stateClass.Instructions.Add(ex); } #endregion // Ajout des fonctions de Access. #region Access foreach (Language.FunctionDeclaration decl in Access.Declarations) { // Membre de l'enum de message enumDecl.Members.Add("MessageType_" + decl.Func.Name); // Classe de message Language.ClankType klassType = new Language.ClankType() { Name = "Access_" + decl.Func.Name + "_Message" }; Language.ClassDeclaration klass = new Language.ClassDeclaration(); klass.Name = klassType.Name; // Création d'un constructeur. Language.Constructor cons = new Language.Constructor(); cons.Owner = klassType; // Création : // Des variables d'instance de la classe. // Des paramètres du constructeur, de l'initialisation de ces paramètres foreach (Language.FunctionArgument arg in decl.Func.Arguments) { Language.Variable argVar = new Language.Variable() { Name = "_" + arg.ArgName, Type = arg.ArgType }; // Déclaration de la variable klass.Instructions.Add(new Language.VariableDeclarationInstruction() { Var = argVar, Modifiers = new List <string>() { "public" } }); // Ajout de l'argument au constructeur. cons.Arguments.Add(arg); // Ajout de l'assignement de la variable cons.Code.Add(new Language.AffectationInstruction() { Expression = new Language.BinaryExpressionGroup() { Operand1 = argVar, Operand2 = new Language.Variable() { Name = arg.ArgName, Type = arg.ArgType }, Operator = Language.Operator.Affectation } }); } // Ajout de la nouvelle classe. klass.Instructions.Add(new Language.ConstructorDeclaration() { Func = cons }); messageClasses.Add(klass); // Déclaration de fonction dans State. stateClass.Instructions.Add(decl); } #endregion #endif //classes.AddRange(messageClasses); classes.AddRange(stateClasses); classes.Add(stateClass); return(classes); }