comparison Lib/Schema.pm @ 0:03e58a454b20

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400
parents
children 16ada169ca75
comparison
equal deleted inserted replaced
-1:000000000000 0:03e58a454b20
1 package Schema;
2 package Schema::TypeName;
3 package Schema::Type;
4 package Schema::Template;
5 package Schema::TemplateSpec;
6 package Schema::Member;
7 package Schema::Property;
8
9 package Schema::TypeName;
10 use Common;
11
12 #our @ISA = qw(Object);
13
14 # ìîæíî îïòèìèçèðîâàòü ïðîèçâîäèòåëüíîñòü, ñîçäàâàÿ îáúåêò ñêàëàÿð äëÿ ïðîñòûõ
15 # èìåí è îáõåêò õåø äëÿ ñïåöèàëèçàöèé
16 # ñäåëàíî
17
18 sub new {
19 my $class = shift;
20 my $this;
21
22 my $name = shift;
23 my @list = map { ref $_ eq 'Schema::TypeName' ? $_ : new Schema::TypeName($_) } @_;
24
25 die new Exception('TypeName soud be a simple identifier',$name) if not $name =~ /^\w+$/;
26
27 if (@list) {
28 $this = bless {}, $class;
29 $this->{Name} = $name;
30 $this->{TemplateList} = \@list if @list;
31 } else {
32 $this = bless \$name, $class;
33 }
34
35 return $this;
36 }
37
38 sub Name {
39 my $this = shift;
40 return (UNIVERSAL::isa($this,'HASH') ? $this->{Name} : $$this);
41 }
42
43 sub Simple {
44 return $_[0]->Name;
45 }
46
47 # ñïèñîê ïàðàìåòðîâ òèïà
48 sub TemplateList {
49 my $this = shift;
50 return (UNIVERSAL::isa($this,'HASH') ? (wantarray ? @{$this->{TemplateList}} : $this->{TemplateList} ) : (wantarray ? return () : undef));
51 }
52
53 # èìÿ òèïà ÿâëÿåòñÿ èìåíåì øàáëîíà
54 sub isTemplateSpec {
55 my $this = shift;
56 return( UNIVERSAL::isa($this,'HASH') ? 1 : 0 );
57 }
58
59 sub CanonicalName {
60 my $this = shift;
61
62 if (UNIVERSAL::isa($this,'HASH')) {
63 if (my $result = $this->{SavedCanonicalName}) {
64 $result;
65 } else {
66 $result = $this->{Name};
67 $result .= '@'. join('#',map {ref $_ eq __PACKAGE__ ? $_->CanonicalName : $_} @{$this->{TemplateList}}) . '@@';
68 $this->{SavedCanonicalName} = $result;
69 }
70 } else {
71 $$this;
72 }
73 }
74
75 sub Canonical {
76 return $_[0]->CanonicalName;
77 }
78
79 # Íå ðåãèñòðèðóåò âíîâü ñîçäàííûõ òèïîâ â òàáëèöå
80 # Ýòî èç-çà ñëó÷àÿ, êîãäà:
81 # MyClass { Hash<int> my_map; }, òîåñòü ïîëó÷åííûé òèï Hahs<int> óæå ñïåöèàëèçèðîâàí è îí áóäåò ñðàçó èíñòàíòèíîðîâàí
82 # DoNotCreate äëÿ ñïåöèàëèçàöèè øàáëîíà òîëüêî ñóùåñòâóþùèìè òèïàìè
83 sub Resolve {
84 my ($this,$TypeTable,$DoNotCreate) = @_;
85
86 if (my $type = $TypeTable->ResolveType($this,$DoNotCreate)) {
87 # ïðåäïîëàãàåòñÿ, ÷òî ñõåìà àâòîìàòè÷åñêè ñîçäàåò ññûëêè âïåðåä íà íåîïðåäåëåííûå ïðîñòûå òèïû
88 return $type;
89 } else {
90 if ($this->isTemplateSpec) {
91 return new Schema::TemplateSpec($this->Name,map {ref $_ eq __PACKAGE__ ? $_->Resolve($TypeTable,$DoNotCreate) : Schema::TypeName->new($_)->Resolve($TypeTable,$DoNotCreate)} @{$this->{TemplateList}} );
92 } else {
93 die new Exception("Simple type not found", $this->Name);
94 }
95 }
96 }
97
98 package Schema::TypeTable;
99 use Common;
100 our @ISA = qw(Object);
101
102 BEGIN {
103 DeclareProperty(Table => ACCESS_NONE);
104 DeclareProperty(NextTable => ACCESS_NONE);
105 }
106
107 sub CTOR {
108 my ($this,$nextTable) = @_;
109 $this->{$NextTable} = $nextTable;
110 }
111
112 sub ResolveType {
113 my ($this,$TypeName,@args) = @_;
114
115 if (my $Type = $this->{$Table}->{$TypeName->CanonicalName}) {
116 return $Type;
117 } elsif($this->{$NextTable}) {
118 return $this->{$NextTable}->ResolveType($TypeName,@args);
119 } else {
120 return undef;
121 }
122 }
123
124 sub RegisterType {
125 my ($this,$Type) = @_;
126
127 if (not $this->{$Table}->{$Type->Name->CanonicalName}) {
128 $this->{$Table}->{$Type->Name->CanonicalName} = $Type;
129 } else {
130 die new Exception("A type already registered",$Type->Name->CanonicalName);
131 }
132 }
133
134 sub _ListTypes {
135 my $this = shift;
136 return values %{$this->{$Table}};
137 }
138
139 sub Dispose {
140 my $this = shift;
141
142 $_->Dispose foreach values %{$this->{$Table} ? $this->{$Table} : {} };
143
144 delete $this->{$Table};
145
146 $this->SUPER::Dispose;
147 }
148
149 # Ñïåöèàëèçàöèÿ øàáëîíà - ýòî èìÿ ñïåöèàëèçèðóåìîãî øàáëîíà è ïàðàìåòðû, êîòîðûå áóäóò åìó ïåðåäàíû (âàæåí ïîðÿäîê ïàðàìåòðîâ)
150 # Ñïåöèàëèçàöèÿ øàáëîíà ïàðàìåòðàìè ïîðàæäàåò ÷àñòè÷íî ñïåöèàëèçèðîâàííûé øàáëîí, êîòîðûé ïî ñóòè òàêæå ÿâëÿåòñÿ øàáëîíîì
151 # Åñëè ñïåöèàëèçàöèÿ ïîëíàÿ, òî ìîæíî ñîçäàòü ýêçåìïëÿð øàáëîíà, òîåñòü ïîëíîöåííûé òèï
152 package Schema::TemplateSpec;
153 use Common;
154 our @ISA = qw(Object);
155
156 BEGIN {
157 DeclareProperty(Name => ACCESS_READ);
158 DeclareProperty(Parameters => ACCESS_READ);
159 DeclareProperty(TemplateList => ACCESS_READ);
160 }
161
162 sub CTOR {
163 my ($this,$templateName,@typeList) = @_;
164
165 my %Params;
166
167 $this->{$TemplateList} = \@typeList;
168
169 # âû÷èñëÿåì ïàðàìåòðû äàííîé ñïåöèàëèçàöèè
170 my @nameList;
171 foreach $typeItem (@typeList) {
172 map { $Params{$_->Name} = $_ } @{$typeItem->Parameters} if $typeItem->isTemplate;
173 push @nameList, $typeItem->Name;
174 }
175
176 $this->{$Parameters} = [ values %Params ];
177 $this->{$Name} = new Schema::TypeName($templateName,@nameList);
178 }
179
180 sub isTemplate {
181 1;
182 }
183
184 sub canInstantinate {
185 my ($this) = @_;
186 if (@{$this->{$Parameters}}) {
187 0;
188 } else {
189 1;
190 }
191 }
192
193 sub Specialize {
194 my ($this,$refParams,$TypeTable) = @_;
195
196 my @specializedList = map {$_->isTemplate && !$_->canInstantinate ? $_->Specialize($refParams,$TypeTable) : $_ } @{$this->{$TemplateList}};
197
198 if ($TypeTable) {
199
200 my $TypeName = new Schema::TypeName($this->Name->Name,map {$_->Name} @specializedList);
201 my $templateSpec = $TypeTable->ResolveType($TypeName);
202 if (not $templateSpec) {
203 $templateSpec = new Schema::TemplateSpec($this->Name->Name,@specializedList);
204 $TypeTable->RegisterType($templateSpec);
205 }
206 return $templateSpec;
207 } else {
208 return new Schema::TemplateSpec($this->Name->Name,@specializedList);
209 }
210 }
211
212 # Ïàðàìåòð øàáëîíà
213 # Ïî ñóòè ÿâëÿåòñÿ øàáëîíîì òèïà Param_Name<T> -> T;
214 package Schema::Parameter;
215
216 sub new {
217 my $TypeName = new Schema::TypeName($_[1]);
218 bless \$TypeName,$_[0];
219 }
220
221 sub Name {
222 ${shift()};
223 }
224
225 sub Specialize {
226 my ($this,$refArgs) = @_;
227 return $refArgs->{$$this->Name};
228 }
229
230 sub isTemplate {
231 1;
232 }
233
234 sub canInstantinate {
235 0;
236 }
237
238 sub Parameters {
239 if (wantarray) {
240 shift;
241 } else {
242 [shift];
243 }
244 }
245
246
247 # ×ëåí êëàññà
248 package Schema::Member;
249 use Common;
250 our @ISA = qw(Object);
251 our $Abstract = 1;
252
253 BEGIN {
254 DeclareProperty(Name => ACCESS_READ);
255 }
256 sub CTOR {
257 my($this,$name) = @_;
258
259 $this->{$Name} = $name;
260 }
261
262 # ×ëåí êëàññà - ñâîéñòâî.
263 # Ñâîéñòâî ìîæåò áûòü øàáëîíîì, åñëè øàáëîíîì ÿâëÿåòñÿ åãî òèï
264 package Schema::Property;
265 use Common;
266 our @ISA = qw(Schema::Member);
267
268 BEGIN {
269 DeclareProperty(Type => ACCESS_READ);
270 }
271
272 sub CTOR {
273 my ($this,$name,$type) = @_;
274 $this->SUPER::CTOR($name);
275
276 $this->{$Type} = $type or die new Exception("A type for the property must be specified",$name);
277 }
278
279 sub isTemplate {
280 my $this = shift;
281 return $this->{$Type}->isTemplate;
282 }
283
284 sub canInstantinate {
285 my $this = shift;
286 return $this->{$Type}->canInstantinate;
287 }
288
289 sub Instantinate {
290 my ($this,$Schema) = @_;
291 return new Schema::Property($this->Name,$Schema->Instantinate($this->{$Type}));
292 }
293
294 sub Specialize {
295 my ($this,$refParams,$TypeTable) = @_;
296 return new Schema::Property($this->Name,$this->{$Type}->Specialize($refParams,$TypeTable));
297 }
298
299 # Òèï, îïèñûâàåò òèï îáúåêòà
300 package Schema::Type;
301 use Common;
302 our @ISA = qw(Object);
303
304 BEGIN {
305 DeclareProperty(Name => ACCESS_READ);
306 DeclareProperty(Schema => ACCESS_READ);
307 DeclareProperty(Members => ACCESS_READ);
308 DeclareProperty(BaseList => ACCESS_READ);
309 DeclareProperty(Attributes => ACCESS_READ); #hash of attributes
310 }
311
312 sub CTOR {
313 my ($this,$argSchema,$name) = @_;
314
315 $this->{$Name} = ref $name eq 'Schema::TypeName' ? $name : new Schema::TypeName($name);
316 $this->{$Schema} = $argSchema;
317 }
318
319 sub isTemplate {
320 0;
321 }
322
323 sub Equals {
324 my ($this,$other) = @_;
325 if (UNIVERSAL::isa($other,'Schema::Type')) {
326 return ($this->Name->CanonicalName eq $other->Name->CanonicalName);
327 } else {
328 return 1;
329 }
330 }
331
332 sub CreateProperty {
333 my ($this,$PropName,$TypeName) = @_;
334
335 $PropType = $this->_ResolveType($TypeName);
336
337 return new Schema::Property($PropName,$PropType);
338 }
339
340 sub AddBase {
341 my ($this,$type) = @_;
342
343 $type = $this->_ResolveType($type);
344
345 not $type->isType($this) or die new Exception('Cant derive from the class which is derived from self', $this->Name->CanonicalName, $type->Name->CanonicalName);
346
347 push @{$this->{$BaseList}},$type;
348 }
349
350 sub isType {
351 my ($this,$type,$maxlevel) = @_;
352
353 return 0 if defined $maxlevel and $maxlevel < 0;
354 my $typeName = UNIVERSAL::isa($type,'Schema::Type') ? $type->Name : $type ;
355
356 return (
357 $this->{$Name}->CanonicalName eq $typeName->CanonicalName ?
358 1
359 :
360 scalar (grep {$_->isType($typeName,defined $maxlevel ? $maxlevel - 1 : undef)} $this->BaseList)
361 );
362 }
363
364 sub ValidateType {
365 my ($this,$type) = @_;
366
367 die new Exception('Can\'t use an unspecialized template',$type->Name->CanonicalName) if ($type->isa('Schema::TypeTemplate'));
368
369 if ($type->isTemplate and not $type->canInstantinate) {
370 die new Exception('Cant use a not fully specialized template in a simple type',$type->Name->CanonicalName, $this->Name->Name) if not $this->isTemplate;
371
372 my %Params = map {$_->Name->Name() , 1} @{$this->Parameters};
373 my @Unresolved = grep {not $Params{$_->Name->Name}} @{$type->Parameters()};
374
375 die new Exception('Not all parameters can be rsolved',map {$_->Name->Name} @Unresolved) if @Unresolved;
376 }
377 }
378
379 sub InsertProperty {
380 my ($this,$PropName,$PropType) = @_;
381
382 $PropType = $this->_ResolveType($PropType);
383
384 my $prop = new Schema::Property($PropName,$PropType);
385
386 push @{$this->{$Members}}, $prop;
387
388 return $prop;
389 }
390
391 sub AddMember {
392 my ($this,$member) = @_;
393
394 push @{$this->{$Members}},$member;
395 }
396
397 sub GetTypeTable {
398 my $this = shift;
399 return $this->{$Schema};
400 }
401
402 sub _ResolveType {
403 my ($this,$type) = @_;
404 if ($type->isa('Schema::TypeName')) {
405 $type = $type->Resolve($this->GetTypeTable());
406 } elsif ($type->isa('Schema::Type') or $type->isa('Schema::TemplateSpec')) {
407 $this->ValidateType($type);
408 } else {
409 die new Exception('Invalid type',$type);
410 }
411
412 $type = $this->{$Schema}->Instantinate($type) if ($type->isTemplate and $type->canInstantinate and not $this->isTemplate);
413 return $type;
414 }
415
416 sub ListMembers {
417 my ($this,%options) = @_;
418
419 my @members;
420
421 if ($options{'foreign'}) {
422 push @members, $_->isa('Schema::Type') ? $_->ListMembers(%options) : () foreach @{$this->{$BaseList} ? $this->{$BaseList} : []};
423 }
424 push @members, @{$this->{$Members} ? $this->{$Members} : []};
425
426 return @members;
427 }
428
429 sub FindMembers {
430 my ($this,$memberName,%options) = @_;
431
432 my @members = grep { $_->Name eq $memberName} @{$this->{$Members} ? $this->{$Members} : []};
433
434 if ($options{'deep'}) {
435 push @members,$_->ListMembers(%options) foreach @{$this->{$BaseList} ? $this->{$BaseList} : []};
436 }
437
438 if(wantarray) {
439 return @members;
440 } else {
441 return shift @members;
442 }
443 }
444
445 sub SetAttributes {
446 my ($this,%attributes) = @_;
447
448 while (my ($key,$value) = each %attributes) {
449 $this->{$Attributes}{$key} = $value;
450 }
451 }
452
453 sub GetAttribute {
454 my ($this,$name) = @_;
455
456 return $this->{$Attributes}{$name};
457 }
458
459 sub _dump {
460 my ($this) = @_;
461 return $this->Name->CanonicalName;
462 }
463
464 sub Dispose {
465 my ($this) = @_;
466
467 undef %{$this};
468 $this->SUPER::Dispose;
469 }
470
471 # Øàáëîí - ïðàìåòðèçîâàííûé òèï
472 package Schema::Template;
473 use Common;
474 our @ISA = qw(Schema::Type);
475
476 BEGIN {
477 DeclareProperty(Parameters => ACCESS_READ);
478 DeclareProperty(LocalTypes => ACCESS_NONE);
479
480 }
481
482 sub CTOR {
483 my ($this,$Schema,$name,@args) = @_;
484 # ïàðàìåòðû íå ÿâëÿþòñÿ ÷à÷òüþ èìåíè
485 $this->SUPER::CTOR($Schema,$name);
486
487 $this->{$Parameters} = [ map {new Schema::Parameter($_) } @args ];
488 my $TypeTable = new Schema::TypeTable($Schema);
489 $TypeTable->RegisterType($_) foreach @{$this->{$Parameters} };
490 $this->{$LocalTypes} = $TypeTable;
491 }
492
493 sub GetTypeTable {
494 my ($this) = @_;
495 return $this->{$LocalTypes};
496 }
497
498 sub isTemplate {
499 1;
500 }
501
502 sub Specialize {
503 my ($this,$refArgs,$TypeTable) = @_;
504
505 my @specializedList = map {$_->Specialize($refArgs)} @{$this->{$Parameters}};
506
507 # ñîçäàåì ñïåöèàëèçàöèþ øàáëîíà
508 my $specializedType;
509
510 if ($TypeTable) {
511 my $TypeName = new Schema::TypeName($this->Name->Name,map {$_->Name} @specializedList);
512
513 if(my $specializedType = $TypeTable->ResolveType($TypeName)) {
514 return $specializedType;
515 } else {
516 $specializedType = new Schema::TemplateSpec($this->Name->Name, @specializedList );
517 $TypeTable->RegisterType($specializedType);
518 return $specializedType;
519 }
520 } else {
521 return new Schema::TemplateSpec($this->Name->Name, @specializedList );
522 }
523 }
524
525 sub canInstantinate {
526 0;
527 }
528
529 # ñîçäàíèå ýêçåìïëÿðà øàáëîíà.
530 # Ñîçäàòü øàáëîí = ïîëíîñòüþ åãî ñïåöèàëèçèðîâàòü
531 # Ïðèíèìàåò íàáîð ïàðàìåòðîâ øàáëîíà è ñîçäàåò íîâûé òèï èëè âîçâðàùàåò èç ñõåìû
532 sub Instantinate {
533 my ($this,$refArgs,$instance) = @_;
534
535 my %ParamInstances;
536 my @TemplateListNames;
537
538 foreach my $param (@{$this->{$Parameters}}) {
539 my $type = $refArgs->{$param->Name->Name};
540 die new Exception("Parameter not specified",$param->Name->Name) if not $type;
541 if ($type->isTemplate) {
542 if ($type->canInstantinate) {
543 $type = $this->Schema->Instantinate($type);
544 } else {
545 die new Exception("Parameter must be a fully speciazlied type",$param->Name->Name);
546 }
547 }
548
549 $ParamInstances{$param->Name->Name} = $type;
550 push @TemplateListNames, $type->Name;
551 }
552
553 # ïàðàìåòðû ïðåäñòàâëÿþò ñîáîé ðåàëüíûå òèïû, ïåðåõîäèì ê ñîçäàíèþ òèïà
554 # äàííàÿ ôóíêöèÿ áåóñëîâíî ñîçäàåò íîâûé òèï, ýòó ôóíêöèþ èñïîëüçóåò ñõåì
555
556 $instance = $this->Schema->CreateType( new Schema::TypeName($this->Name->Name,@TemplateListNames) ) if not $instance;
557
558 $instance->SetAttributes(%{$this->Attributes}) if $this->Attributes;
559 $instance->SetAttributes(
560 TemplateInstance => {
561 Template => $this,
562 Parameters => \%ParamInstances
563 }
564 );
565
566 foreach my $Ancestor ($this->BaseList) {
567 $instance->AddBase(
568 $Ancestor->isTemplate ?
569 ( $Ancestor->canInstantinate ?
570 $this->Schema->Instantinate($Ancestor)
571 :
572 $this->Schema->Instantinate($Ancestor->Specialize(\%ParamInstances,$this->GetTypeTable))
573 )
574 :
575 $Ancestor
576 );
577 }
578
579 foreach my $Member ($this->Members) {
580 $instance->AddMember(
581 $Member->isTemplate ?
582 ($Member->canInstantinate ?
583 $Member->Instantinate($this->Schema)
584 :
585 $Member->Specialize(\%ParamInstances,$this->GetTypeTable)->Instantinate($this->Schema)
586 )
587 :
588 $Member
589 );
590 }
591
592 return $instance;
593 }
594
595 sub _ResolveType {
596 my ($this,$type) = @_;
597 if ($type->isa('Schema::TypeName')) {
598 $type = $type->Resolve($this->GetTypeTable());
599 if (not $this->{$LocalTypes}->ResolveType($type->Name)) {
600 $this->{$LocalTypes}->RegisterType($type);
601 }
602 } elsif ($type->isa('Schema::Type') or $type->isa('Schema::TemplateSpec')) {
603 $this->ValidateType($type);
604 } else {
605 die new Exception('Invalid type',$type);
606 }
607
608 return $type;
609 }
610
611
612 package Schema;
613 use strict;
614 use Common;
615 our @ISA = qw(Schema::TypeTable);
616
617 BEGIN {
618 DeclareProperty(PendingInstances => ACCESS_NONE);
619 DeclareProperty(UnresolvedTypes => ACCESS_NONE);
620 }
621
622 sub CTOR {
623
624 }
625
626 # Ñõåìà àâòîìàòè÷åñêè ñîçäàåò ññûëêè âïåðåä íà íåñóùåñòâóþùèå ïðîñòûå òèïû
627 sub ResolveType {
628 my ($this,$TypeName,$DoNotCreate) = @_;
629
630 if (my $type = $this->SUPER::ResolveType($TypeName)) {
631 return $type;
632 } else {
633 if (not $TypeName->isTemplateSpec and not $DoNotCreate) {
634 $type = new Schema::Type($this,$TypeName);
635 $this->RegisterType($type);
636 $this->{$UnresolvedTypes}->{$TypeName->CanonicalName} = $TypeName;
637 return $type;
638 } else {
639 return undef;
640 }
641 }
642 }
643
644 sub CreateType {
645 my ($this,$TypeName) = @_;
646
647 $TypeName = new Schema::TypeName($TypeName) if ref $TypeName ne 'Schema::TypeName';
648
649 if (my $type = $this->SUPER::ResolveType($TypeName)) {
650 if ($this->{$UnresolvedTypes}->{$TypeName->CanonicalName}) {
651 delete $this->{$UnresolvedTypes}->{$TypeName->CanonicalName};
652 return $type;
653 } else {
654 die new Exception("Type already exists",$TypeName->CanonicalName);
655 }
656 } else {
657 $type = new Schema::Type($this,$TypeName);
658 $this->SUPER::RegisterType($type);
659 return $type;
660 }
661 }
662
663 sub CreateTemplate {
664 my ($this,$TemplateName,@ParamNames) = @_;
665
666 die new Exception("Parameters required for the template") if not @ParamNames;
667
668 if (ref $TemplateName eq 'Schema::TypeName') {
669 die new Exception('Template specialization is not valid name for a new template',$TemplateName->CanonicalName) if $TemplateName->isTemplateSpec;
670 } else {
671 $TemplateName = new Schema::TypeName($TemplateName);
672 }
673
674 if (my $type = $this->SUPER::ResolveType($TemplateName)) {
675 die new Exception('Type already exists');
676 } else {
677 $type = new Schema::Template($this,$TemplateName,@ParamNames);
678 $this->SUPER::RegisterType($type);
679 return $type;
680 }
681 }
682
683 # ñîçäàíèå ýêçåìïëÿðà øàáëîíà
684 # ñîçäàåòñÿ íîâûé ïóñòîé òèï, äîáàâëÿåòñÿ â PendingInstances
685 sub Instantinate {
686 my ($this,$TemplateSpec) = @_;
687
688 # ïðè ñïåöèàëèçàöèè íàïðìåð ýòîãî: T m_var; ïîëó÷èì äëÿ èíñòàíòèíèöèè real_type m_var; è íå ïðîâåðÿÿ îòäàäèì åãî íà ñïåöèàëèçàöèþ,
689 # âîò è îáðàáîòêà
690 return $TemplateSpec if not $TemplateSpec->isTemplate;
691
692 die new Exception('Only a template specialization can be instantinated') if ref $TemplateSpec ne 'Schema::TemplateSpec';
693 die new Exception('Only fully specialized template can be instantinated') if not $TemplateSpec->canInstantinate;
694
695 my $TypeName = $TemplateSpec->Name;
696
697 if (my $type = $this->SUPER::ResolveType($TypeName)) {
698 return $type;
699 } else {
700 $type = new Schema::Type($this,$TypeName);
701 $this->SUPER::RegisterType($type);
702 push @{$this->{$PendingInstances}},[$TemplateSpec,$type];
703 return $type;
704 }
705 }
706
707 sub Close {
708 my ($this) = @_;
709
710 if (keys %{$this->{$UnresolvedTypes}}) {
711 die new Exception('Some type definitions are absent',keys %{$this->{$UnresolvedTypes}});
712 }
713
714 if ($this->{$PendingInstances}) {
715 while( my $ref = shift @{$this->{$PendingInstances}} ) {
716 my ($spec,$instance) = @$ref;
717 if (my $typeTemplate = $this->SUPER::ResolveType( new Schema::TypeName($spec->Name->Name) )) {
718 die new Exception('Can\'t instantinate a specialization of the simple type',$instance->Name->CanonicalName) if not $typeTemplate->isTemplate;
719 if (scalar(@{$typeTemplate->Parameters}) == scalar(@{$spec->TemplateList})) {
720 my @Params = @{$typeTemplate->Parameters};
721 $typeTemplate->Instantinate({map { (shift @Params)->Name->Name, $_ } @{$spec->TemplateList}},$instance);
722 } else {
723 die new Exception('A template parameters doesn\'t match to the specialization list',$instance->Name->CanonicalName);
724 }
725 } else {
726 die new Exception('Can\'t instantinate a specialization, the specified template isn\'t found', $instance->Name->CanonicalName);
727 }
728 }
729
730 delete $this->{$PendingInstances};
731 }
732 }
733
734 sub EnumTypes {
735 my ($this,%options) = @_;
736
737 return grep { ($_->isTemplate and not $options{'skip_templates'}) or (not $_->isTemplate and not $options{'skip_classes'}) } $this->_ListTypes;
738 }
739
740 sub Dispose {
741 my ($this) = @_;
742
743 delete $this->{$UnresolvedTypes};
744
745 $this->SUPER::Dispose;
746 }
747
748 1;