// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; namespace PascalABCCompiler.TreeRealization { /// /// Базовый класс для программ и dll. /// [Serializable] public abstract class program_base : definition_node, SemanticTree.IProgramBase { /// /// Расположение конструкции program имя_программы, или главного модуля dll. /// private location _loc; /// /// Список модулей, используемых в программе. /// private readonly common_unit_node_list _units = new common_unit_node_list(); /// /// Список пространств имен в программе. /// private common_namespace_node[] _namespaces = null; /// /// Конструктор класса. /// /// Расположение конструкции program имя_программы, или главного модуля dll. public program_base(location loc) { _loc = loc; } /// /// Расположение конструкции program имя_программы, или главного модуля dll. /// public location loc { get { return _loc; } } /// /// Список модулей, используемых в программе или dll. /// public common_unit_node_list units { get { return _units; } } /// /// Обобщенный тип узла. /// public override general_node_type general_node_type { get { return general_node_type.program_node; } } //TODO: Исправить этот метод, так чтобы он работал только с корневыми или со всеми пространствами имен. /// /// Просматривает список модулей, и объединяет одни и те-же пространства имен разных модулей. /// /// Список модулей. /// Список пространств имен. private static common_namespace_node[] get_units_namespaces(common_unit_node_list units) { /*System.Collections.Generic.Dictionary namespaces = new System.Collections.Generic.Dictionary( SystemLibrary.SystemLibrary.string_comparer); foreach (common_unit_node un in units) { foreach (common_namespace_node cnn in un.namespaces) { string full_name = cnn.namespace_full_name; common_namespace_node new_namespace; if (!(namespaces.TryGetValue(full_name,out new_namespace))) { new_namespace = cnn.clone(); namespaces[full_name] = new_namespace; } else { new_namespace.merge_with_namespace(cnn); } } } common_namespace_node[] ret = new common_namespace_node[namespaces.Count]; namespaces.Values.CopyTo(ret, 0); return ret;*/ var ht = new Dictionary(); var al = new List(); common_namespace_node main_cnn = null; foreach (common_unit_node un in units) { foreach (common_namespace_node cnn in un.namespaces) { //if (cnn.namespace_full_name != "") //{ if (!ht.ContainsKey(cnn.namespace_name)) { al.Add(cnn); ht[cnn.namespace_name] = cnn; } //else // throw new Errors.CompilerInternalError("MergeNamespaces", new Errors.LocatedError("Dupblicate nammespace name: "+cnn.namespace_name)); //} //else main_cnn = cnn; } } int num = 0; if (main_cnn != null) num++; common_namespace_node[] namespaces_to_ret = new common_namespace_node[al.Count + num]; if (main_cnn != null) namespaces_to_ret[0] = main_cnn; al.CopyTo(namespaces_to_ret, num); return namespaces_to_ret; /*System.Collections.Hashtable ht = new System.Collections.Hashtable(); System.Collections.ArrayList al = new System.Collections.ArrayList(); foreach (common_unit_node un in units) { foreach (common_namespace_node cnn in un.namespaces) if (ht[cnn.namespace_name] == null) { al.Add(cnn); ht[cnn.namespace_name] = cnn; } } common_namespace_node[] namespaces_to_ret = new common_namespace_node[al.Count]; al.CopyTo(namespaces_to_ret); return namespaces_to_ret;*/ } private List _used_namespaces = new List(); public string[] UsedNamespaces { get { return _used_namespaces.ToArray(); } } /// /// Массив пространств имен, используемых в программе. /// public common_namespace_node[] common_namespaces { get { if (_namespaces == null) { _namespaces = get_units_namespaces(_units); var ns_ht = new HashSet(); foreach (common_unit_node un in units) { foreach (string s in un.used_namespaces) { if (!ns_ht.Contains(s)) { this._used_namespaces.Add(s); ns_ht.Add(s); } } } } return _namespaces; } } /// /// Массив пространств имен, используемых в программе. /// Используется при обходе дерева посетителем. /// public SemanticTree.ICommonNamespaceNode[] namespaces { get { return common_namespaces; } } /// /// Расположение конструкции program имя_программы, или главного модуля dll. /// Используется при обходе дерева посетителем. /// public SemanticTree.ILocation Location { get { return _loc; } } /// /// Метод для обхода дерева посетителем. /// /// Класс - посетитель дерева. public override void visit(SemanticTree.ISemanticVisitor visitor) { visitor.visit(this); } } /// /// Класс, представляющий всю программу. /// [Serializable] public class program_node : program_base, SemanticTree.IProgramNode { /// /// Главная процедура без параметров. Включает в себя вызовы процедур инициализации модулей (и финализации тоже). /// Она определена только здесь. Отсюда ее и надо компилировать в выходной код. /// private common_namespace_function_node _main_function; private bool _internal_dll = false; /// /// Конструктор класса. /// /// Главная функция программы. /// Расположение программы. public program_node(common_namespace_function_node main_function,location loc) : base(loc) { _main_function=main_function; } public bool internal_dll { get { return _internal_dll; } set { _internal_dll = value; } } static HashSet graph_modules = new HashSet(new string[] { "GraphABC", "GraphWPF", "Graph3D", "PlotWPF", "Robot", "RobotField", "RobotZadan", "RobotTaskMaker", "Drawman", "DrawManField", "ABCObjects", "ABCButtons", "ABCHouse", "ABCSprites", "WPFObjects", "TurtleWPF", "Turtle", "Мозаика", "МозаикаABC", "FormsABC", "Чертежник", "Робот"}); public void create_main_function(string[] used_stand_modules, Dictionary config) { add_needed_cctors(); common_namespace_function_node temp = _main_function; _main_function = new common_namespace_function_node("Main", null, null, (common_namespace_node)_main_function.comprehensive_namespace, null); location loc = temp.loc; statements_list sl = new statements_list(loc); _main_function.function_code = sl; // if (units[0].MainArgsParameter!=null) // { // _main_function.parameters.AddElement(units[0].MainArgsParameter); // sl.statements.AddElement(units[0].MainArgsAssignExpr); // } // if (units[0].IsConsoleApplicationVariableAssignExpr!=null) // { // sl.statements.AddElement(units[0].IsConsoleApplicationVariableAssignExpr); // } statements_list sl2 = sl; sl = new statements_list(null); common_namespace_function_node init_func = new common_namespace_function_node("$_Init_",null,null,(common_namespace_node)_main_function.comprehensive_namespace,null); ((common_namespace_node)_main_function.comprehensive_namespace).functions.AddElement(init_func); namespace_variable init_var = new namespace_variable("$is_init",SystemLibrary.SystemLibrary.bool_type,(common_namespace_node)_main_function.comprehensive_namespace,null); ((common_namespace_node)_main_function.comprehensive_namespace).variables.AddElement(init_var); if (SystemLibrary.SystemLibInitializer.ConfigVariable != null && SystemLibrary.SystemLibInitializer.ConfigVariable.Found) { namespace_variable conf_nv = null; compiled_variable_definition conf_cf = null; if (SystemLibrary.SystemLibInitializer.ConfigVariable.sym_info is namespace_variable) conf_nv = SystemLibrary.SystemLibInitializer.ConfigVariable.sym_info as namespace_variable; else conf_cf = SystemLibrary.SystemLibInitializer.ConfigVariable.sym_info as compiled_variable_definition; foreach (string config_var in config.Keys) { var config_value = config[config_var]; compiled_function_call cfc = new compiled_function_call(compiled_function_node.get_compiled_method(NetHelper.NetHelper.AddToDictionaryMethod), (conf_nv != null) ? (expression_node)new namespace_variable_reference(conf_nv, null) : (expression_node)new static_compiled_variable_reference(conf_cf, null), null); cfc.parameters.AddElement(new string_const_node(config_var, null)); switch (Type.GetTypeCode(config_value.GetType())) { case TypeCode.String: cfc.parameters.AddElement(new string_const_node((string)config_value, null)); break; case TypeCode.Int32: cfc.parameters.AddElement(new int_const_node((int)config_value, null)); break; case TypeCode.Boolean: cfc.parameters.AddElement(new bool_const_node((bool)config_value, null)); break; case TypeCode.Double: cfc.parameters.AddElement(new double_const_node((double)config_value, null)); break; default: throw new NotSupportedException("Config value type is nort supported"); } sl.statements.AddElement(cfc); } } if (units[0].MainArgsParameter!=null) { _main_function.parameters.AddElement(units[0].MainArgsParameter); sl.statements.AddElementFirst(units[0].MainArgsAssignExpr); } if (units[0].IsConsoleApplicationVariableAssignExpr!=null) { sl.statements.AddElementFirst(units[0].IsConsoleApplicationVariableAssignExpr); } else if (SystemLibrary.SystemLibInitializer.ConfigVariable?.sym_info is compiled_variable_definition && units[0].IsConsoleApplicationVariableValue.constant_value) { bool is_console = true; foreach (var ns in units[0].used_namespaces) { if (graph_modules.Contains(ns)) { is_console = false; break; } } if (is_console) { var ccnf = SystemLibrary.SystemLibInitializer.ConfigVariable.sym_info as compiled_variable_definition; basic_function_call bbfc = new basic_function_call(SystemLibrary.SystemLibrary.bool_assign as basic_function_node, null); bbfc.parameters.AddElement(new static_compiled_variable_reference(ccnf.cont_type.find_in_type(StringConstants.IsConsoleApplicationVariableName)[0].sym_info as compiled_variable_definition, ccnf.cont_type, null)); bbfc.parameters.AddElement(new bool_const_node(true, null)); sl.statements.AddElement(bbfc); } } for (int i = 0; i < units.Count; i++) { if (units[i].main_function != null) { if (units[i].main_function.name != StringConstants.temp_main_function_name) { common_namespace_function_call cnfc = new common_namespace_function_call(units[i].main_function, loc); sl.statements.AddElement(cnfc); } else { common_namespace_function_call cnfc = new common_namespace_function_call(units[i].main_function, loc); sl2.statements.AddElement(cnfc); } } } //if (units.Count == 1) for (int i = 0; i < used_stand_modules.Length; i++) { Type t = NetHelper.NetHelper.FindRtlType(used_stand_modules[i] + "." + used_stand_modules[i]); if (t == null) continue; compiled_type_node ctn = compiled_type_node.get_type_node(t); System.Reflection.MethodInfo mi = ctn.compiled_type.GetMethod("__InitModule__"); if (mi == null) { continue; } compiled_static_method_call csmc = new compiled_static_method_call(compiled_function_node.get_compiled_method(mi), null); sl.statements.AddElement(csmc); } for (int i = units.Count - 1; i >= 0; i--) { if (units[i].finalization_method != null) { common_namespace_function_call cnfc = new common_namespace_function_call(units[i].finalization_method, loc); sl2.statements.AddElement(cnfc); } } //if (units.Count == 1) for (int i = 0; i < used_stand_modules.Length; i++) { Type t = NetHelper.NetHelper.FindRtlType(used_stand_modules[i] + "." + used_stand_modules[i]); if (t == null) continue; compiled_type_node ctn = compiled_type_node.get_type_node(t); System.Reflection.MethodInfo mi = ctn.compiled_type.GetMethod("__FinalizeModule__"); if (mi == null) continue; compiled_static_method_call csmc = new compiled_static_method_call(compiled_function_node.get_compiled_method(mi), null); sl2.statements.AddElement(csmc); } sl2 = new statements_list(loc); basic_function_call bfc = new basic_function_call(SystemLibrary.SystemLibrary.bool_assign as basic_function_node,null); bfc.parameters.AddElement(new namespace_variable_reference(init_var,null)); bfc.parameters.AddElement(new bool_const_node(true,null)); sl.statements.AddElementFirst(bfc); bfc = new basic_function_call(SystemLibrary.SystemLibrary.bool_not as basic_function_node,null); bfc.parameters.AddElement(new namespace_variable_reference(init_var,null)); sl2.statements.AddElement(new if_node(bfc,sl,null,null)); init_func.function_code = sl2; sl = new statements_list(null); sl.statements.AddElement(new common_namespace_function_call(init_func,null)); common_namespace_function_node init_variables_func = new common_namespace_function_node("$_InitVariables_", null, null, (common_namespace_node)_main_function.comprehensive_namespace, null); init_variables_func.function_code = new statements_list(null); ((common_namespace_node)_main_function.comprehensive_namespace).functions.AddElement(init_variables_func); sl.statements.AddElement(new common_namespace_function_call(init_variables_func,null)); _init_code = sl; } public void create_main_function_as_in_module() { add_needed_cctors(); statements_list sl = new statements_list(loc); statements_list intern_sl = new statements_list(loc); statements_list sl2 = sl; sl = new statements_list(null); common_namespace_function_node init_func = new common_namespace_function_node("$_Init_", null, null, common_namespaces[0], null); common_namespaces[0].functions.AddElement(init_func); namespace_variable init_var = new namespace_variable("$is_init", SystemLibrary.SystemLibrary.bool_type, common_namespaces[0], null); common_namespaces[0].variables.AddElement(init_var); for (int i = 0; i < units.Count; i++) { if (units[i].main_function != null) { common_namespace_function_call cnfc = new common_namespace_function_call(units[i].main_function, loc); sl.statements.AddElement(cnfc); } } /*for (int i = units.Count - 1; i >= 0; i--) { if (units[i].finalization_method != null) { common_namespace_function_call cnfc = new common_namespace_function_call(units[i].finalization_method, loc); sl.statements.AddElement(cnfc); } }*/ sl2 = new statements_list(loc); basic_function_call bfc = new basic_function_call(SystemLibrary.SystemLibrary.bool_assign as basic_function_node, null); bfc.parameters.AddElement(new namespace_variable_reference(init_var, null)); bfc.parameters.AddElement(new bool_const_node(true, null)); sl.statements.AddElementFirst(bfc); bfc = new basic_function_call(SystemLibrary.SystemLibrary.bool_not as basic_function_node, null); bfc.parameters.AddElement(new namespace_variable_reference(init_var, null)); sl2.statements.AddElement(new if_node(bfc, sl, null, null)); init_func.function_code = sl2; _init_code = new common_namespace_function_call(init_func, null); add_initialization_to_cctors(); } private void add_needed_cctors() { foreach (common_namespace_node cnn in common_namespaces) { foreach (common_type_node ctn in cnn.types) { if (!ctn.IsInterface && ctn.static_constr == null) { ctn.static_constr = new common_method_node(StringConstants.static_ctor_prefix + StringConstants.default_constructor_name, null, ctn, SemanticTree.polymorphic_state.ps_static, SemanticTree.field_access_level.fal_private, null); ctn.static_constr.is_constructor = true; ctn.static_constr.function_code = new statements_list(null); ctn.methods.AddElement(ctn.static_constr); (ctn.static_constr.function_code as statements_list).statements.AddElement(new return_node(null, null)); } } } } private void add_initialization_to_cctors() { foreach (common_namespace_node cnn in common_namespaces) { if (cnn.is_main) { foreach (common_type_node ctn in cnn.types) { if (ctn.static_constr == null) { ctn.static_constr = new common_method_node(StringConstants.static_ctor_prefix + StringConstants.default_constructor_name, null, ctn, SemanticTree.polymorphic_state.ps_static, SemanticTree.field_access_level.fal_private, null); ctn.static_constr.is_constructor = true; ctn.static_constr.function_code = new statements_list(null); ctn.methods.AddElement(ctn.static_constr); (ctn.static_constr.function_code as statements_list).statements.AddElement(new return_node(null, null)); } (ctn.static_constr.function_code as statements_list).statements.AddElementFirst(_init_code); } } else { } } } private statement_node _init_code; public statement_node initialization_code { get { return _init_code; } } SemanticTree.IStatementNode SemanticTree.IProgramNode.InitializationCode { get { return _init_code; } } /// /// Главная функция. Ее выполнение равносильно выполнению программы. /// Она включает вызовы методов инициализации модулей (в начале), выполнение основной программы /// и вызовы методов финализации модулей. /// public common_namespace_function_node main_function { get { return _main_function; } set { _main_function = value; } } /// /// Тип узла. /// public override semantic_node_type semantic_node_type { get { return semantic_node_type.program_node; } } /// /// Метод для обхода дерева посетителем. /// /// Класс - посетитель дерева. public override void visit(SemanticTree.ISemanticVisitor visitor) { visitor.visit(this); } SemanticTree.ICommonNamespaceFunctionNode SemanticTree.IProgramNode.main_function { get { return _main_function; } } public System.Collections.Generic.List generic_type_instances { get { return generic_convertions.all_type_instances; } } public System.Collections.Generic.List generic_function_instances { get { return generic_convertions.all_function_instances; } } } [Serializable] public class dll_node : program_base, SemanticTree.IDllNode { /// /// Метод инициализации dll. Он определен только здесь. /// Отсюда его и надо компилировать в выходной код. /// private common_namespace_function_node _initialization_function; /// /// Метод финализации dll. Он определен только здесь. /// Отсюда его и надо компилироавть в выходной код. /// private common_namespace_function_node _finalization_function; /// /// Конструктор корневого узла dll. /// /// Метод инициализации dll. /// Метод финализации dll. /// Расположение заголовка главного unit-а dll. public dll_node(common_namespace_function_node initialization_function, common_namespace_function_node finalization_function, location loc) : base(loc) { _initialization_function=initialization_function; _finalization_function=finalization_function; } /// /// Метод инициализации dll. /// public common_namespace_function_node initialization_function { get { return _initialization_function; } } /// /// Метод финализации dll. /// public common_namespace_function_node finalization_function { get { return _finalization_function; } } /// /// Тип узла. /// public override semantic_node_type semantic_node_type { get { return semantic_node_type.dll_node; } } /// /// Метод для обхода дерева посетителем. /// /// Класс - посетитель дерева. public override void visit(SemanticTree.ISemanticVisitor visitor) { visitor.visit(this); } SemanticTree.ICommonNamespaceFunctionNode SemanticTree.IDllNode.initialization_function { get { return _initialization_function; } } SemanticTree.ICommonNamespaceFunctionNode SemanticTree.IDllNode.finalization_function { get { return _finalization_function; } } } }