/branches/matreshka-0.1.x/design/amf2/gen-stage1/generator-driver.adb

http://github.com/landgraf/matreshka · Ada · 638 lines · 397 code · 125 blank · 116 comment · 18 complexity · 99c20287e10d02316f61fc2d0070f682 MD5 · raw file

  1. with Ada.Command_Line;
  2. with Ada.Strings.Fixed;
  3. with Ada.Strings.Maps;
  4. with Ada.Strings.Unbounded;
  5. with Ada.Text_IO;
  6. with Dom.Core.Elements;
  7. with Dom.Core.Nodes;
  8. with Dom.Readers;
  9. with Sax.Readers;
  10. with Input_Sources.File;
  11. with Analyzer;
  12. with Generator.Attributes;
  13. with Generator.Constructors;
  14. with Generator.Metamodel;
  15. with Generator.Reflection;
  16. with Generator.Subclassing;
  17. with Generator.Utilities;
  18. procedure Generator.Driver is
  19. use Ada.Strings;
  20. use Ada.Strings.Fixed;
  21. use Ada.Strings.Maps;
  22. use Ada.Strings.Unbounded;
  23. use Ada.Text_IO;
  24. use Analyzer;
  25. use Generator.Attributes;
  26. use Generator.Constructors;
  27. use Generator.Metamodel;
  28. use Generator.Reflection;
  29. use Generator.Subclassing;
  30. use Generator.Utilities;
  31. Cmof_Namespace : constant String :=
  32. "http://schema.omg.org/spec/MOF/2.0/cmof.xml";
  33. Xmi_Namespace : constant String := "http://schema.omg.org/spec/XMI/2.1";
  34. procedure Process_Tree (N : Dom.Core.Node);
  35. procedure Process_Element (N : Dom.Core.Node);
  36. procedure Process_Children (N : Dom.Core.Node);
  37. procedure Process_Class (N : Dom.Core.Node);
  38. procedure Process_Package (N : Dom.Core.Node);
  39. procedure Process_Property (N : Dom.Core.Node);
  40. procedure Process_Association (N : Dom.Core.Node);
  41. procedure Process_Primitive_Type (N : Dom.Core.Node);
  42. procedure Process_Enumeration (N : Dom.Core.Node);
  43. function Get_Attribute
  44. (Node : Dom.Core.Node;
  45. Name : String;
  46. Default : Boolean) return Boolean;
  47. function Get_Attribute
  48. (Node : Dom.Core.Node;
  49. Name : String;
  50. Default : Natural) return Natural;
  51. function Get_Attribute
  52. (Node : Dom.Core.Node;
  53. Name : String) return Unbounded_String_Sets.Set;
  54. function Get_Attribute
  55. (Node : Dom.Core.Node;
  56. Name : String) return Unbounded_String_Vectors.Vector;
  57. -- Current context
  58. Current_Association : Association_Access := null;
  59. Current_Class : Class_Access := null;
  60. -------------------
  61. -- Get_Attribute --
  62. -------------------
  63. function Get_Attribute
  64. (Node : Dom.Core.Node;
  65. Name : String;
  66. Default : Boolean) return Boolean
  67. is
  68. use Dom.Core.Elements;
  69. V : constant String := Get_Attribute (Node, Name);
  70. begin
  71. if V'Length = 0 then
  72. return Default;
  73. else
  74. return Boolean'Value (V);
  75. end if;
  76. end Get_Attribute;
  77. -------------------
  78. -- Get_Attribute --
  79. -------------------
  80. function Get_Attribute
  81. (Node : Dom.Core.Node;
  82. Name : String;
  83. Default : Natural) return Natural
  84. is
  85. use Dom.Core.Elements;
  86. V : constant String := Get_Attribute (Node, Name);
  87. begin
  88. if V'Length = 0 then
  89. return Default;
  90. else
  91. if V = "*" then
  92. return Natural'Last;
  93. else
  94. return Natural'Value (V);
  95. end if;
  96. end if;
  97. end Get_Attribute;
  98. -------------------
  99. -- Get_Attribute --
  100. -------------------
  101. function Get_Attribute
  102. (Node : Dom.Core.Node;
  103. Name : String) return Unbounded_String_Sets.Set
  104. is
  105. use Dom.Core.Elements;
  106. Separators : constant Character_Set := To_Set (" ");
  107. Value : constant String := Get_Attribute (Node, Name);
  108. First : Positive := Value'First;
  109. Last : Natural;
  110. begin
  111. return Result : Unbounded_String_Sets.Set do
  112. loop
  113. Find_Token
  114. (Value (First .. Value'Last), Separators, Outside, First, Last);
  115. exit when First > Last;
  116. Result.Insert (To_Unbounded_String (Value (First .. Last)));
  117. First := Last + 1;
  118. end loop;
  119. end return;
  120. end Get_Attribute;
  121. -------------------
  122. -- Get_Attribute --
  123. -------------------
  124. function Get_Attribute
  125. (Node : Dom.Core.Node;
  126. Name : String) return Unbounded_String_Vectors.Vector
  127. is
  128. use Dom.Core.Elements;
  129. Separators : constant Character_Set := To_Set (" ");
  130. Value : constant String := Get_Attribute (Node, Name);
  131. First : Positive := Value'First;
  132. Last : Natural;
  133. begin
  134. return Result : Unbounded_String_Vectors.Vector do
  135. loop
  136. Find_Token
  137. (Value (First .. Value'Last), Separators, Outside, First, Last);
  138. exit when First > Last;
  139. Result.Append (To_Unbounded_String (Value (First .. Last)));
  140. First := Last + 1;
  141. end loop;
  142. end return;
  143. end Get_Attribute;
  144. ----------
  145. -- Hash --
  146. ----------
  147. -- function Hash (Item : Class_Access) return Ada.Containers.Hash_Type is
  148. -- begin
  149. -- return Ada.Strings.Unbounded.Hash (Item.Name);
  150. -- end Hash;
  151. ----------
  152. -- Hash --
  153. ----------
  154. -- function Hash (Item : Element_Access) return Ada.Containers.Hash_Type is
  155. -- begin
  156. -- return Ada.Strings.Unbounded.Hash (Item.Name);
  157. -- end Hash;
  158. -------------------------
  159. -- Process_Association --
  160. -------------------------
  161. procedure Process_Association (N : Dom.Core.Node) is
  162. use Dom.Core.Elements;
  163. Id : constant String :=
  164. Get_Attribute_NS (N, Xmi_Namespace, "id");
  165. Name : constant String := Get_Attribute (N, "name");
  166. Member_End : Unbounded_String_Vectors.Vector :=
  167. Get_Attribute (N, "memberEnd");
  168. New_Association : Association_Access;
  169. begin
  170. -- Put_Line (Standard_Error, " Process association: '" & Name & "' [" & Id & ']');
  171. New_Association :=
  172. new Association_Record'
  173. (Id => To_Unbounded_String (Id),
  174. Name => To_Unbounded_String (Name),
  175. First_End => Member_End.First_Element,
  176. Second_End => Member_End.Last_Element,
  177. Owned_End => Property_Sets.Empty_Set);
  178. Elements.Insert (New_Association.Id, Element_Access (New_Association));
  179. Associations.Insert (New_Association);
  180. Current_Association := New_Association;
  181. Process_Children (N);
  182. Current_Association := null;
  183. end Process_Association;
  184. ----------------------
  185. -- Process_Children --
  186. ----------------------
  187. procedure Process_Children (N : Dom.Core.Node) is
  188. use Dom.Core;
  189. use Dom.Core.Nodes;
  190. C : Node := First_Child (N);
  191. begin
  192. while C /= null loop
  193. case Node_Type (C) is
  194. when Element_Node =>
  195. Process_Element (C);
  196. when others =>
  197. null;
  198. end case;
  199. C := Next_Sibling (C);
  200. end loop;
  201. end Process_Children;
  202. -------------------
  203. -- Process_Class --
  204. -------------------
  205. procedure Process_Class (N : Dom.Core.Node) is
  206. use Dom.Core.Elements;
  207. Id : constant String
  208. := Get_Attribute_NS (N, Xmi_Namespace, "id");
  209. Name : constant String := Get_Attribute (N, "name");
  210. Is_Abstract : constant Boolean
  211. := Get_Attribute (N, "isAbstract", False);
  212. Super_Classes : constant Unbounded_String_Sets.Set
  213. := Get_Attribute (N, "superClass");
  214. New_Class : Class_Access;
  215. begin
  216. -- Ada.Text_IO.Put_Line ("Process class: '" & Name & "' [" & Id & ']');
  217. New_Class :=
  218. new Class_Record'
  219. (Id => To_Unbounded_String (Id),
  220. Name => To_Unbounded_String (Name),
  221. Is_Abstract => Is_Abstract,
  222. Super_Classes => Super_Classes,
  223. Properties => Property_Sets.Empty_Set,
  224. All_Properties => Property_Full_Sets.Empty_Set,
  225. Expansion => Property_Expansion_Maps.Empty_Map,
  226. Collection_Slots => 0);
  227. Elements.Insert (New_Class.Id, Element_Access (New_Class));
  228. Classes.Insert (New_Class);
  229. Current_Class := New_Class;
  230. Process_Children (N);
  231. Current_Class := null;
  232. end Process_Class;
  233. ---------------------
  234. -- Process_Element --
  235. ---------------------
  236. procedure Process_Element (N : Dom.Core.Node) is
  237. use Dom.Core.Elements;
  238. Type_Name : constant String :=
  239. Get_Attribute_NS (N, Xmi_Namespace, "type");
  240. begin
  241. if Type_Name = "cmof:Association" then
  242. Process_Association (N);
  243. elsif Type_Name = "cmof:Class" then
  244. Process_Class (N);
  245. elsif Type_Name = "cmof:Comment" then
  246. null;
  247. elsif Type_Name = "cmof:Constraint" then
  248. null;
  249. elsif Type_Name = "cmof:Enumeration" then
  250. Process_Enumeration (N);
  251. elsif Type_Name = "cmof:Operation" then
  252. null;
  253. elsif Type_Name = "cmof:Package" then
  254. Process_Package (N);
  255. elsif Type_Name = "cmof:PackageImport" then
  256. null;
  257. elsif Type_Name = "cmof:PrimitiveType" then
  258. Process_Primitive_Type (N);
  259. elsif Type_Name = "cmof:Property" then
  260. Process_Property (N);
  261. else
  262. raise Program_Error with "Unable to dispatch " & Type_Name;
  263. end if;
  264. end Process_Element;
  265. -------------------------
  266. -- Process_Enumeration --
  267. -------------------------
  268. procedure Process_Enumeration (N : Dom.Core.Node) is
  269. use Dom.Core.Elements;
  270. Id : constant String
  271. := Get_Attribute_NS (N, Xmi_Namespace, "id");
  272. Name : constant String := Get_Attribute (N, "name");
  273. New_Enumeration : Enumeration_Access;
  274. begin
  275. New_Enumeration :=
  276. new Enumeration_Record'
  277. (Id => To_Unbounded_String (Id),
  278. Name => To_Unbounded_String (Name));
  279. Elements.Insert
  280. (New_Enumeration.Id, Element_Access (New_Enumeration));
  281. Enumerations.Insert (New_Enumeration);
  282. end Process_Enumeration;
  283. ---------------------
  284. -- Process_Package --
  285. ---------------------
  286. procedure Process_Package (N : Dom.Core.Node) is
  287. use Dom.Core.Elements;
  288. Name : constant String := Get_Attribute (N, "name");
  289. begin
  290. if Name = "Core"
  291. or else Name = "Constructs"
  292. or else Name = "PrimitiveTypes"
  293. then
  294. Process_Children (N);
  295. end if;
  296. end Process_Package;
  297. ----------------------------
  298. -- Process_Primitive_Type --
  299. ----------------------------
  300. procedure Process_Primitive_Type (N : Dom.Core.Node) is
  301. use Dom.Core.Elements;
  302. Id : constant String
  303. := Get_Attribute_NS (N, Xmi_Namespace, "id");
  304. Name : constant String := Get_Attribute (N, "name");
  305. New_Primitive_Type : Primitive_Type_Access;
  306. begin
  307. New_Primitive_Type :=
  308. new Primitive_Type_Record'
  309. (Id => To_Unbounded_String (Id),
  310. Name => To_Unbounded_String (Name));
  311. Elements.Insert
  312. (New_Primitive_Type.Id, Element_Access (New_Primitive_Type));
  313. Primitive_Types.Insert (New_Primitive_Type);
  314. end Process_Primitive_Type;
  315. ----------------------
  316. -- Process_Property --
  317. ----------------------
  318. procedure Process_Property (N : Dom.Core.Node) is
  319. use Dom.Core.Elements;
  320. Id : constant String
  321. := Get_Attribute_NS (N, Xmi_Namespace, "id");
  322. Name : constant String := Get_Attribute (N, "name");
  323. Type_Id : Unbounded_String
  324. := To_Unbounded_String (Get_Attribute (N, "type"));
  325. Lower : constant Natural := Get_Attribute (N, "lower", 1);
  326. Upper_Value : constant String := Get_Attribute (N, "upper");
  327. Upper : Natural;
  328. Is_Read_Only : constant Boolean
  329. := Get_Attribute (N, "isReadOnly", False);
  330. Is_Derived : constant Boolean
  331. := Get_Attribute (N, "isDerived", False);
  332. Is_Derived_Union : constant Boolean
  333. := Get_Attribute (N, "isDerivedUnion", False);
  334. Redefined_Property : constant String
  335. := Get_Attribute (N, "redefinedProperty");
  336. Is_Ordered : constant Boolean
  337. := Get_Attribute (N, "isOrdered", False);
  338. Is_Unique : constant Boolean
  339. := Get_Attribute (N, "isUnique", True);
  340. Is_Composite : constant Boolean
  341. := Get_Attribute (N, "isComposite", False);
  342. Default_Value : constant String := Get_Attribute (N, "default");
  343. -- subsettedProperty
  344. -- association
  345. New_Property : Property_Access;
  346. begin
  347. if Length (Type_Id) = 0 then
  348. if Name = "raisedException" then
  349. Type_Id := To_Unbounded_String ("Core-Constructs-Type");
  350. elsif Name = "ownedParameter" then
  351. Type_Id := To_Unbounded_String ("Core-Constructs-Parameter");
  352. else
  353. Put_Line
  354. (Standard_Error,
  355. "Property '" & Id & "'/'" & Name & "' type not specified");
  356. end if;
  357. end if;
  358. if Upper_Value = "" then
  359. Upper := 1;
  360. elsif Upper_Value = "*" then
  361. Upper := Natural'Last;
  362. else
  363. Upper := Natural'Value (Upper_Value);
  364. end if;
  365. New_Property :=
  366. new Property_Record'
  367. (Id => To_Unbounded_String (Id),
  368. Name => To_Unbounded_String (Name),
  369. Type_Id => Type_Id,
  370. Lower => Lower,
  371. Upper => Upper,
  372. Is_Read_Only => Is_Read_Only,
  373. Is_Derived => Is_Derived,
  374. Is_Derived_Union => Is_Derived_Union,
  375. Is_Ordered => Is_Ordered,
  376. Is_Unique => Is_Unique,
  377. Is_Composite => Is_Composite,
  378. Owned_Class => Current_Class,
  379. Owned_Association => Current_Association,
  380. Association => Current_Association,
  381. Redefined_Property_Id =>
  382. To_Unbounded_String (Redefined_Property),
  383. Redefined_Property => null,
  384. Has_Default => False,
  385. Default_Boolean => False,
  386. Default_Integer => 0);
  387. if Default_Value /= "" then
  388. if Has_Boolean_Type (New_Property) then
  389. New_Property.Has_Default := True;
  390. New_Property.Default_Boolean := Boolean'Value (Default_Value);
  391. elsif Has_Integer_Type (New_Property) then
  392. New_Property.Has_Default := True;
  393. New_Property.Default_Integer := Integer'Value (Default_Value);
  394. elsif Has_Unlimited_Natural_Type (New_Property) then
  395. New_Property.Has_Default := True;
  396. if Default_Value = "*" then
  397. New_Property.Default_Integer := Integer'Last;
  398. else
  399. New_Property.Default_Integer := Integer'Value (Default_Value);
  400. end if;
  401. end if;
  402. end if;
  403. Elements.Insert (New_Property.Id, Element_Access (New_Property));
  404. if Current_Class /= null then
  405. Current_Class.Properties.Insert (New_Property);
  406. elsif Current_Association /= null then
  407. Current_Association.Owned_End.Insert (New_Property);
  408. end if;
  409. end Process_Property;
  410. ------------------
  411. -- Process_Tree --
  412. ------------------
  413. procedure Process_Tree (N : Dom.Core.Node) is
  414. use Dom.Core;
  415. use Dom.Core.Elements;
  416. use Dom.Core.Nodes;
  417. C : Node := First_Child (First_Child (N));
  418. begin
  419. while C /= null loop
  420. case Node_Type (C) is
  421. when Element_Node =>
  422. if Local_Name (C) = "Package" then
  423. if Get_Attribute (C, "name") = "InfrastructureLibrary" then
  424. Process_Children (C);
  425. end if;
  426. end if;
  427. when others =>
  428. null;
  429. end case;
  430. C := Next_Sibling (C);
  431. end loop;
  432. end Process_Tree;
  433. ----------------------------
  434. -- Generate_Element_Kinds --
  435. ----------------------------
  436. -- procedure Generate_Element_Kinds;
  437. -- Generates kinds of items in the element table. The set consists from
  438. -- all non-abstract classes and special value N_None.
  439. -- procedure Generate_Element_Kinds is
  440. --
  441. -- procedure Process_Class (Position : Class_Sets.Cursor);
  442. --
  443. -- function To_Ada (Name : String) return String;
  444. --
  445. -- function To_Ada (Name : String) return String is
  446. -- Aux : String (1 .. Name'Length * 2);
  447. -- Last : Natural := 0;
  448. --
  449. -- begin
  450. -- for J in Name'Range loop
  451. -- if J = Name'First then
  452. -- Last := Last + 1;
  453. -- Aux (Last) := To_Upper (Name (J));
  454. --
  455. -- else
  456. -- if Is_Upper (Name (J)) then
  457. -- Last := Last + 1;
  458. -- Aux (Last) := '_';
  459. -- end if;
  460. --
  461. -- Last := Last + 1;
  462. -- Aux (Last) := Name (J);
  463. -- end if;
  464. -- end loop;
  465. --
  466. -- return Aux (Aux'First .. Last);
  467. -- end To_Ada;
  468. --
  469. -- -------------------
  470. -- -- Process_Class --
  471. -- -------------------
  472. --
  473. -- procedure Process_Class (Position : Class_Sets.Cursor) is
  474. -- Element : Class_Access := Class_Sets.Element (Position);
  475. --
  476. -- begin
  477. -- if not Element.Is_Abstract then
  478. -- Ada.Text_IO.Put_Line (",");
  479. -- Ada.Text_IO.Put (" E_" & To_Ada (To_String (Element.Name)));
  480. -- end if;
  481. -- end Process_Class;
  482. --
  483. -- begin
  484. -- Ada.Text_IO.New_Line;
  485. -- Ada.Text_IO.Put_Line (" type Element_Kinds is");
  486. -- Ada.Text_IO.Put (" (E_None");
  487. -- Classes.Iterate (Process_Class'Access);
  488. -- Ada.Text_IO.Put_Line (");");
  489. -- end Generate_Element_Kinds;
  490. File : Input_Sources.File.File_Input;
  491. Reader : Dom.Readers.Tree_Reader;
  492. begin
  493. Input_Sources.File.Open (Ada.Command_Line.Argument (1), File);
  494. Dom.Readers.Set_Feature (Reader, Sax.Readers.Namespace_Feature, True);
  495. Dom.Readers.Set_Feature
  496. (Reader, Sax.Readers.Namespace_Prefixes_Feature, True);
  497. Dom.Readers.Parse (Reader, File);
  498. Process_Tree (Dom.Readers.Get_Tree (Reader));
  499. Dom.Readers.Free (Reader);
  500. Input_Sources.File.Close (File);
  501. Analyze;
  502. -- Generate_Element_Kinds;
  503. Generate_Metamodel_Specification;
  504. Generate_Metamodel_Implementation;
  505. Generate_Subclassing_Specification;
  506. Generate_Subclassing_Implementation;
  507. Generate_Attribute_Mappings_Specification;
  508. Generate_Attributes_Specification;
  509. Generate_Attributes_Implementation;
  510. Generate_Constructors_Specification;
  511. Generate_Constructors_Implementation;
  512. Generate_Reflection_Implementation;
  513. end Generator.Driver;