How come child packages are only possible for library level packages?
I now encountered a situation where I'd like to create a child
package of a nested package:
-- file: pkg.ads
package Pkg is
package Nested is
type Object is tagged null record;
end Nested;
end Pkg;
-- file: pkg-nested-child.ads
package Pkg.Nested.Child is
type Derived is new Object with null record;
end Pkg.Nested.Child;
(The only thing that crosses my naive mind is that this makes
life harder for the Ada compiler in that if a file pkg-nested.ads
cannot be found then the compiler would need to look inside pkg.ads
to see if the parent to which the child refers can be found there.)
Thanks,
O. Kellogg
> I now encountered a situation where I'd like to create a child
> package of a nested package:
>
> -- file: pkg.ads
> package Pkg is
> package Nested is
> type Object is tagged null record;
> end Nested;
> end Pkg;
>
> -- file: pkg-nested-child.ads
> package Pkg.Nested.Child is
> type Derived is new Object with null record;
> end Pkg.Nested.Child;
It looks like you tried to create a *grandchild* package without first
creating a child package. Sort of a double immaculate conception. :-)
Try declaring Pkg.Nested.Child within Pkg.
--
T.E.D.
Home - mailto:denn...@telepath.com (Yahoo: Ted_Dennison)
Homepage - http://www.telepath.com/dennison/Ted/TED.html
Well, my point was not wanting to do that.
Imagine Pkg to be the production of a code generator, potentially
containing hundreds of these nested packages, while Pkg.Nested.Child
is a human written extension.
One reason for wanting nested packages might be to reduce the number
of files.
Another, more important reason is that further declarations in
Pkg might depend on things from the nested packages, for example
-- near the end of package Pkg:
type Object_Array array (1 .. 2) of Nested.Object;
Thanks,
Oliver Kellogg
> denn...@telepath.com (Ted Dennison) wrote:
> >
> > Try declaring Pkg.Nested.Child within Pkg.
>
> Well, my point was not wanting to do that.
> Imagine Pkg to be the production of a code generator, potentially
> containing hundreds of these nested packages, while Pkg.Nested.Child
> is a human written extension.
I hope you can influence the automatic tool to produce code that lets
you do what you need to do :). This is the base of automatic tools;
they always need tweeking, and some don't allow the user sufficient
power to do the tweeking.
You might consider using separate subunits, declared in the body of
Pkg. But you probably need tool support for that as well.
--
-- Stephe
MDC
--
Marin David Condic
Senior Software Engineer
Pace Micro Technology Americas www.pacemicro.com
Enabling the digital revolution
e-Mail: marin....@pacemicro.com
The CORBA IDL to Ada mapping prescribes that nested IDL modules,
interfaces, and valuetypes be mapped to child packages.
This mapping is fundamentally flawed.
Example:
// IDL
module A {
interface B {
typedef short type_in_b;
void my_method ();
};
typedef B::type_in_b type_in_a;
};
Since the interface B is mapped to a child package A.B, it is not
possible to map type_in_a to Ada.
The solution is to map nested IDL units to nested Ada packages.
However, IDL interfaces and valuetypes require implementations.
For example, the IDL to Ada mapping prescribes that the
implementation of interface A::B be done in a child package of
A.B named A.B.Impl. It would certainly be the preferable to
maintain this mapping, but that's not possible with Ada right now.
-- Oliver Kellogg
Why can't "type_in_a" be put inside the same "A" package as "B"? That
would compile, and would seem to be the natural mapping of this.
Sorry, I don't understand. What exactly do you mean?
As soon as interface B is mapped as a child package A.B,
there is no way A can "with" its own child A.B ?
No. I didn't say to make B a child package of A. Instead I am talking
about nesting B's child inside of A along with B.
In the CORBA context, this would mean intertwining hand written code
with automatically generated code:
A.B is automatically generated while A.B.Impl is hand written.
--
Er, sorry, I've just clicked the wrong button and sent this to Oliver by
e-mail:
Just a quick idea - maybe using "is separate" in some right places would
solve it? Like having the spec of A.B.Impl inside A.B, and having the body
separate.
Sergey Koshcheyev.
> Just a quick idea - maybe using "is separate" in some right places would
> solve it? Like having the spec of A.B.Impl inside A.B, and having the body
> separate.
That's definitely possible, but still only a workaround solution.
The real solution IMO is to permit nested packages as units that are
interchangeable with child packages in package hierarchies.
I.e. everywhere that a child package may appear, also a nested
package could appear.
It should be at the software archtiect's freedom how he chooses to
physically lay out a unit in the hierarchy - as a child package or as
a nested package.
Oliver Kellogg
I don't know enough about nested packages and separates to say if/how
this would work. But issues like this are the reason "is separate" is
in the language.
Names : List_Id := New_List (Defining_Unit_Name (Specification (Decl)));
in the bottom page of the added code block below.
Later, while Analyze_Use_Package loops through the Names, the Nkind
of the (first and only) name node appears not to have been set.
I'm sure there's something wrong with the way I synthesize the use
clause. Help, anyone?
*** par-load.adb.orig Thu Mar 14 10:59:36 2002
--- par-load.adb Tue Apr 23 22:25:25 2002
***************
*** 290,301 ****
Unum :=
Load_Unit
(Load_Name => Spec_Name,
! Required => True,
Subunit => False,
Error_Node => Curunit);
if Unum /= No_Unit then
Set_Parent_Spec (Unit (Curunit), Cunit (Unum));
end if;
end if;
--- 290,383 ----
Unum :=
Load_Unit
(Load_Name => Spec_Name,
! Required => False,
Subunit => False,
Error_Node => Curunit);
if Unum /= No_Unit then
Set_Parent_Spec (Unit (Curunit), Cunit (Unum));
+ else
+ -- The Spec_Name may refer to a nested package.
+ Spec_Name := Get_Parent_Spec_Name (Spec_Name);
+ if Spec_Name /= No_Name then
+ Unum :=
+ Load_Unit
+ (Load_Name => Spec_Name,
+ Required => True,
+ Subunit => False,
+ Error_Node => Curunit);
+ if Unum /= No_Unit then
+ Set_Parent_Spec (Unit (Curunit), Cunit (Unum));
+ -- Check that the referenced nested package exists.
+ declare
+ function Infix (Threefix : String) return String;
+ -- Given a name "A.B.C", returns "B".
+ -- Returns "" if the input name does not contain
+ -- two periods.
+ function Infix (Threefix : String) return String is
+ I1 : Natural := Threefix'First;
+ I2 : Natural;
+ begin
+ while I1 <= Threefix'Last
+ and then Threefix (I1) /= '.' loop
+ I1 := I1 + 1;
+ end loop;
+ if I1 = Threefix'Last then
+ return "";
+ end if;
+ I1 := I1 + 1;
+ I2 := I1;
+ while I2 <= Threefix'Last
+ and then Threefix (I2) /= '.' loop
+ I2 := I2 + 1;
+ end loop;
+ if I2 = Threefix'Last then
+ return "";
+ end if;
+ return Threefix (I1 .. I2 - 1);
+ end Infix;
+ Found : Boolean := False;
+ Spec : Node_Id := Specification (Unit (Cunit (Unum)));
+ Decls : List_Id := Visible_Declarations (Spec);
+ Decl : Node_Id := First (Decls);
+ Nested_Name : String
+ := Infix (Get_Name_String (Unit_Name (Cur_Unum)));
+ Pkg_Name : Name_Id;
+ begin
+ while Present (Decl) loop
+ if Nkind (Decl) = N_Package_Declaration then
+ Pkg_Name :=
+ Chars (Defining_Unit_Name (Specification (Decl)))
;
+ if Get_Name_String (Pkg_Name) = Nested_Name then
+ Found := True;
+ exit;
+ end if;
+ end if;
+ Next (Decl);
+ end loop;
+ if Found then
+ Set_Parent_Spec (Unit (Curunit), Cunit (Unum));
+ -- Synthesize a use clause for the parent package.
+ declare
+ Names : List_Id
+ := New_List
+ (Defining_Unit_Name (Specification (Decl)));
+ Use_Nested_Parent : Node_Id
+ := Make_Use_Package_Clause (Loc, Names);
+ begin
+ Prepend_To
+ (Visible_Declarations
+ (Specification (Unit (Curunit))),
+ Use_Nested_Parent);
+ Mark_Rewrite_Insertion (Use_Nested_Parent);
+ end;
+ else
+ Error_Msg ("parent package not found", Loc);
+ end if;
+ end;
+
+ end if;
+ end if;
end if;
end if;
FYI:
Turned out that during parsing, one should never directly assign a
synthesized node from already constructed nodes.
Reason: The constructed nodes have additional fields set that make the
compiler assume the new node has already been semantically analyzed.
Instead, use New_Node (or the Nmake.Make_ methods) in combination with
Chars and other accessors to copy the individual node fields.
I'll refrain from attaching the corrected diff, mail me if you
want it.
Next, I'll look at how to make visible to the child the nested parent's
private part.