File Coverage

yapp/astma2-fact.yp
Criterion Covered Total %
statement 225 231 97.4
branch 141 154 91.5
condition 26 39 66.6
subroutine 52 52 100.0
pod 0 2 0.0
total 444 478 92.8


line stmt bran cond sub pod time code
1             %{
2 1     1   19 use Data::Dumper;
  1         3  
  1         216  
3 1     1   6 use TM;
  1         3  
  1         45  
4 1     1   2017 use TM::Literal;
  1         4  
  1         56  
5              
6             use constant {
7 1         2400 XSD => 'http://www.w3.org/2001/XMLSchema',
8             XSD_STRING => 'http://www.w3.org/2001/XMLSchema#string',
9             ASTMA => 'http://psi.tm.bond.edu.au/astma/2.0/',
10             ONTOLOGY => 'http://psi.tm.bond.edu.au/astma/2.0/#ontology',
11             TEMPLATE => 'http://psi.tm.bond.edu.au/astma/2.0/#template'
12 1     1   10 };
  1         3  
13              
14             sub _expand_template {
15 12     12   116 my $store = shift;
16 12         22 my $ted = shift;
17 12         16 my $params = shift; # they are all strings at this level
18              
19             #warn "params".Dumper $params;
20              
21 12 100       72 my @returns = $store->match (TM->FORALL, type => 'return', irole => 'thing', iplayer => $store->tids ($ted) )
22             or die "template '$ted' does not have a 'return' characteristic";
23             #warn Dumper \@returns;
24 11 50 100     108 my $return = $returns[0]->[TM->PLAYERS]->[1] and (scalar @returns == 1
25             or die "ambiguous 'return' characteristics for '$ted'");
26              
27 10 50 50     47 my $value = $return->[0] and ($return->[1] eq 'http://www.w3.org/2001/XMLSchema#string'
28             or die "'return' characteristic of '$ted' is no string");
29             #warn "template id '$ted' >>>$value<<<";
30 10         32 foreach my $p (keys %$params) {
31 22         500 $value =~ s/{\s*\$$p\s*}/$params->{$p}/sg;
32             }
33             #warn "after template id '$ted' >>>$value<<<";
34 10 100       56 die "variable '$1' in template '$ted' has no value at expansion" if $value =~ /{\s*(\$\w+)\s*}/;
35 9         60 return $value;
36             }
37              
38             %}
39              
40             %token DUMMY
41 83     83 0 1723  
42 83         289 %token EOL
43 83   66     440 %token DOT
44             %token BRA
45 83 50       302 %token KET
46             %token URI
47             %token TILDE
48             %token EQUAL
49             %token COLON
50             %token NAME
51             %token OCC
52             %token VALUE
53             %token HAS
54             %token DOWNCOMMA
55             %token COMMA
56             %token WHICH
57             %token TED
58             %token REIFIES
59             %token ISREIFIED
60             %token LPAREN
61             %token RPAREN
62              
63             %token SUBCL
64             %token ISA
65              
66             %token LOG
67             %token CANCEL
68             %token VERSION
69             %token INCLUDE
70              
71              
72             %token COMMENT
73             %token WILDCARD
74             %token DATE
75              
76             %token BN
77             %token OC
78             %token IN
79             %token SIN
80             %token STRING
81             %token ID
82             %token ISINDICATEDBY
83             %token LBRACKET
84             %token RBRACKET
85             %token AT
86              
87             %%
88              
89              
90              
91             instance : # empty
92             | instance EOL
93             | instance clause
94             ;
95              
96 163     163   4266 clause : { $_[0]->{USER}->{ctx} = undef; }
97             theme DOT
98             | template_expansion
99             | directive
100             ;
101              
102 1     1   52 directive : CANCEL { die "Cancelled"; }
103 1     1   49 | LOG { warn $_[1]; 1; } # write message to STDERR
  1         4  
104 2 100   2   90 | VERSION { die "unsupported version $_[1]" unless $_[1] =~ /^2\./; 1; }
  1         3  
105             | INCLUDE {
106 2     2   61 my $content;
107              
108 2 100       13 if ($_[1] =~ /\|\s*$/) { # a pipe | at the end, this is a UNIX pipe
109 1   50     15 my $fh = IO::File->new ($_[1]) || die "unable to open pipe '$_[1]'";
110 1         25688 local $/ = undef;
111 1         3847 $content = <$fh>;
112 1         69 $fh->close;
113             } else {
114 1     1   1165 use LWP::Simple;
  1         101253  
  1         11  
115 1   50     9 $content = get($_[1]) || die "unable to load '$_[1] with LWP'\n";
116             }
117             #warn "new content >>>$content<<<";
118 2         43626 $_[0]->YYData->{INPUT} = $content . $_[0]->YYData->{INPUT}; # prepend it
119             }
120             | ENCODING {
121 1     1   638 use Encode;
  1         2  
  1         5503  
122 1     1   32 Encode::from_to ($_[0]->YYData->{INPUT}, "iso-8859-1", $_[1]);
123             }
124             ;
125              
126 4     4   120 template_expansion : TED parameters { $_[0]->YYData->{INPUT} .= "\n" .
127             _expand_template ($_[0]->{USER}->{store},
128             $_[1],
129             $_[2]) # compute the expanded version
130             . "\n"; # extend the text at the end;
131             }
132             ;
133              
134             parameters : # empty
135 54     54   1005 { { } }
136 6     6   184 | LPAREN bindings RPAREN { $_[2] }
137             ;
138              
139             bindings : binding
140 4     4   129 | bindings COMMA binding { $_[1] = { %{$_[1]}, %{$_[3]} }; $_[1]; } # combine the hashes
  4         12  
  4         16  
  4         13  
141             ;
142              
143 10     10   360 binding : ID COLON { $_[0]->{USER}->{value} = 1 } VALUE { { "$_[1]" => $_[4]->[0] } } # create a small hash (and use the string)
  10         361  
144             ;
145              
146             theme : BRA topic KET
147             | topic
148             ;
149              
150 205     205   8032 topic : { unshift @{$_[0]->{USER}->{ctx}}, undef; } # push a (yet unknown) topic
  205         931  
151             attachments
152             association
153             ;
154              
155             association : # empty
156 30     30   1836 | REIFIES { $_[0]->{USER}->{reifier} = $_[0]->{USER}->{ctx}->[0];
157 30         124 $_[0]->{USER}->{ctx}->[0] = undef;
158             }
159 29     29   1194 identification { $_[0]->{USER}->{atype} = $_[0]->{USER}->{ctx}->[0];
160 29         124 $_[0]->{USER}->{assoc} = 1; # indicate to lexer that we are in assoc context
161             }
162             scope
163             rolesin roles rolesout
164             {
165             # warn "roles :". Dumper $_[7];
166 22         126 $_[0]->{USER}->{store}->assert ([ $_[0]->{USER}->{reifier}, # LID
167             $_[5], # SCOPE
168             $_[0]->{USER}->{atype}, # TYPE
169             TM->ASSOC, # KIND
170 22     22   1675 @{$_[7]}, # ROLES, PLAYERS
171             undef ] );
172 22 100       75 $_[0]->{USER}->{implicits}->{'isa-scope'}->{$_[5]}++ if $_[5];
173 22         79 $_[0]->{USER}->{assoc} = undef; # indicate to lexer that we left assoc context
174             }
175             ;
176              
177             rolesin : LPAREN | EOL
178             ;
179             rolesout : # empty
180             | RPAREN
181             | EOL
182             ;
183             rolesep : COMMA | EOL
184             ;
185              
186             roles : role
187             | roles rolesep role {
188 15     15   478 push @{$_[1]->[0]}, @{$_[3]->[0]};
  15         41  
  15         31  
189 15         27 push @{$_[1]->[1]}, @{$_[3]->[1]};
  15         34  
  15         34  
190 15         42 $_[1];
191             }
192             ;
193              
194 42     42   3179 role : topic { $_[0]->{USER}->{role} = $_[0]->{USER}->{ctx}->[0] }
195 40     40   1902 COLON { $_[0]->{USER}->{ctx}->[0] = undef } # clean out context
196             identifications {
197 38     38   918 [ [ ($_[0]->{USER}->{role}) x scalar @{$_[5]} ], $_[5] ]
  38         179  
198             }
199             ;
200              
201 38     38   1383 identifications : identification { $_[0]->{USER}->{ctx}->[0] = undef } # clean out context here
202 38     38   1187 { [ $_[1] ] }
203 4     4   215 | identifications identification { $_[0]->{USER}->{ctx}->[0] = undef }
204 4     4   109 { push @{$_[1]}, $_[2]; $_[1]; }
  4         11  
  4         9  
205             ;
206              
207             attachments : # empty
208             | attachments HAS characteristic
209             | attachments WHICH HAS characteristic
210             | attachments expansion
211             | attachments WHICH expansion
212             | attachments identification
213             | attachments EOL identification
214             ;
215              
216             relative : # empty
217             | DOWNCOMMA attachments upcomma
218             ;
219              
220             upcomma : # empty
221             | COMMA
222             ;
223              
224 42     42   1421 predefined_inlines : ISA { 'isa' }
225 7     7   311 | SUBCL { 'subclasses' }
226             | TED
227             ;
228              
229 56     56   1950 expansion : predefined_inlines parameters { unshift @{$_[0]->{USER}->{ctx}}, undef; } identification
  56         268  
230             {
231             # warn " expand ctx ".Dumper $_[0]->{USER}->{ctx};
232 56     56   2260 my $left = $_[0]->{USER}->{ctx}->[1];
233 56         92 my $ted = $_[1];
234 56         128 my $right = $_[0]->{USER}->{ctx}->[0];
235 56         125 my $store = $_[0]->{USER}->{store};
236 56         76 my $params = $_[2];
237              
238             #warn "left $left ted $ted right $right";
239              
240 56 100       184 if ($ted eq 'subclasses') {
    100          
    50          
241 7         75 $store->assert ([ undef, # LID
242             undef, # SCOPE
243             'is-subclass-of', # TYPE
244             TM->ASSOC, # KIND
245             [ 'subclass', 'superclass' ], # ROLES
246             [ $left, $right ], # PLAYERS
247             undef ] );
248             } elsif ($ted eq 'isa') {
249 41         407 $store->assert ([ undef, # LID
250             undef, # SCOPE
251             'isa', # TYPE
252             TM->ASSOC, # KIND
253             [ 'instance', 'class' ], # ROLES
254             [ $left, $right ], # PLAYERS
255             undef ] );
256             } elsif ($ted eq 'hasa') { # same, but other way round
257 0         0 $store->assert ([ undef, # LID
258             undef, # SCOPE
259             'isa', # TYPE
260             TM->ASSOC, # KIND
261             [ 'instance', 'class' ], # ROLES
262             [ $right, $left ], # PLAYERS
263             undef ] );
264             } else {
265 8         35 $_[0]->YYData->{INPUT} .= "\n" .
266             _expand_template ($store,
267             $ted,
268             { %$params,
269             '_left' => $left,
270             '_right' => $right}) # compute the expanded version
271             . "\n"; # extend the text at the end;
272             }
273             }
274              
275 54     54   2994 relative { shift @{$_[0]->{USER}->{ctx}}; } # clean out context
  54         223  
276             ;
277              
278             identification : tid {
279             # warn "tid: >>".$_[1]."<<";
280 302 100   302   9285 if (! defined $_[1]) { # wildcard
    100          
    100          
281 7   66     73 $_[0]->{USER}->{ctx}->[0] ||= $_[0]->{USER}->{store}->internalize (sprintf "uuid-%010d", $TM::toplet_ctr++);
282             } elsif (ref ($_[1])) { # reference means indicator
283 34         171 $_[0]->{USER}->{ctx}->[0] = $_[0]->{USER}->{store}->internalize ($_[0]->{USER}->{ctx}->[0] => $_[1]);
284             } elsif ($_[1] =~ /^\w+:.+/) { # URI means subject address
285 6         38 $_[0]->{USER}->{ctx}->[0] = $_[0]->{USER}->{store}->internalize ($_[0]->{USER}->{ctx}->[0] => $_[1]);
286             } else { # some lousy identifier
287             # warn "checking for context ".Dumper $_[0]->{USER}->{ctx}->[0] ;
288 255 100       3555 die "duplicate ID: $_[1] and $_[0]->{USER}->{ctx}->[0]"
289             if ($_[0]->{USER}->{ctx}->[0]); # we already have an identifier!
290 252         1134 $_[0]->{USER}->{ctx}->[0] = $_[0]->{USER}->{store}->internalize ($_[1]);
291             }
292 299         1304 $_[1] = $_[0]->{USER}->{ctx}->[0]; # whatever that was, that's it
293             }
294             ;
295              
296 84     84   6929 characteristic : tid scope type COLON { $_[0]->{USER}->{value} = 1 } VALUE
297             {
298 81     81   2986 my $ctype = $_[1];
299 81         98 my $cclass; # we do not yet know what this will be
300 81 100       352 if ($_[3]) { # there is a type specified
    100          
301 8         18 $cclass = $_[3]; # take this to be the class of what ctype is
302             } elsif ($_[1] =~ /.*name$/) { # looks like a name
303 37 100       116 if ($_[6]->[1] eq XSD_STRING) { # but we check first what type the value is
304 36         60 $cclass = 'name'; # for a string we allow it to be a name
305             } else {
306 1         4 $cclass = 'occurrence'; # otherwise, we guess it is an occurrence
307             }
308             } else { # type does not end with 'name'
309 36         60 $cclass = 'occurrence'; # this is then an occurrence
310             }
311              
312 81 100       227 if ($cclass ne $ctype) { # a new instance was introduced
313 37         281 $store->assert ([ undef, # LID
314             undef, # SCOPE
315             'is-subclass-of', # TYPE
316             TM->ASSOC, # KIND
317             [ 'subclass', 'superclass' ], # ROLES
318             [ $ctype, $cclass ], # PLAYERS
319             undef ] );
320             }
321             # warn "char $_[1] ctx ".Dumper $_[0]->{USER}->{ctx};
322 81 100       1008 $_[0]->{USER}->{store}->assert ( #
    100          
323             [
324             undef, # LID
325             $_[2], # SCOPE (undef is ok)
326             $_[1], # TYPE
327              
328             $cclass eq 'name' ? TM->NAME
329             :
330             ($cclass eq 'occurrence' ? TM->OCC
331             : TM->ASSOC), # KIND
332             [ 'thing', 'value' ], # ROLES
333             [ $_[0]->{USER}->{ctx}->[0], $_[6] ], # PLAYERS
334             undef
335             ]
336             );
337             }
338             ;
339              
340             scope : # empty
341 9     9   275 | AT tid { $_[2]; }
342             ;
343              
344             type : # empty
345 8     8   274 | SUBCL tid { $_[2] }
346             ;
347              
348              
349             ctype : NAME
350             | OCC
351             ;
352              
353 342     342   22200 tid : ID { $_[1]; }
354 7     7   368 | WILDCARD { undef; } # make sure we have an ID
355 4     4   180 | DATE { \ $_[1]; }
356 6     6   202 | EQUAL URI { $_[2]; }
357 8     8   295 | TILDE URI { \ $_[2]; }
358             | URI {
359 36     36   1408 my $baseuri = $_[0]->{USER}->{store}->baseuri;
360 36 100       280 $_[1] =~ /^$baseuri(.+)/ ? $1 : \ $_[1];
361             }
362 83         31316 ;
363              
364              
365 83         7300 #-------------------------------------------
366 83         437  
367             xinstance : # empty
368             | instance EOL
369             | instance theme
370             ;
371              
372             xxxtopic : identification involvements
373             ;
374              
375             xinvolvements : # empty
376             | involvements involvement
377             ;
378              
379             involvement : identification
380             | AND attachment
381             | attachment
382             | LRELATIVE relative RRELATIVE
383             ;
384              
385             xattachment : statement
386             ;
387              
388             statement : ISA topic
389             ;
390              
391              
392              
393              
394              
395              
396             xxtopic : tid
397             {
398             warn "involve ".Dumper $_[2];
399             1;
400             }
401             ;
402              
403             tids : tid { [ $_[1] ] } # singleton
404             | tids tid { push @{$_[1]}, $_[2]; $_[1] }
405             ;
406              
407             involvements : { [] } #empty
408             | involvements inlined_expansion { push @{$_[1]}, $_[2]; $_[1] }
409             ;
410              
411             inlined_expansion : LPAREN tids RPAREN { $_[2] }
412             ;
413              
414             #types : { [] } # empty
415             # | types type { push @{$_[1]}, @{$_[2]}; $_[1] }
416             #;
417             #
418             #type : ISA ID { [ $_[2] ] }
419             # | LPAREN ids RPAREN { $_[2] }
420             #;
421              
422              
423              
424              
425              
426             xtopic : ID types reification_indication inline_assocs EOL
427             {
428             $_[1] = $_[0]->{USER}->{store}->internalize ($_[1]);
429              
430             if (ref $_[3]) { # we have reification info
431             if ( $_[3]->[0] == 1) { # 1 = REIFIES, means current ID is a shorthand for the other
432             $_[0]->{USER}->{store}->internalize ($_[1] => $_[3]->[1]);
433             } elsif ($_[3]->[0] == 0) { # 0 = IS-REIFIED, this must be the other way round
434             $_[0]->{USER}->{store}->internalize ($_[3]->[1] => $_[1]);
435             } elsif ($_[3]->[0] == 2) { # 2 = ISINDICATEDBY, add the subject indicators
436             $_[0]->{USER}->{store}->internalize ($_[1] => \ $_[3]->[1]);
437             } else {
438             die "internal fu**up";
439             }
440             }
441             # assert instance/class
442             if (@{$_[2]}) {
443             $_[0]->{USER}->{store}->assert ( map {
444             [ undef,
445             undef,
446             'isa',
447             undef,
448             [ 'class', 'instance' ],
449             [ $_, $_[1] ],
450             ]}
451             @{$_[2]} );
452             }
453             { # memorize that the types should be a 'topic' at the end (see end of parse)
454             my $implicits = $_[0]->{USER}->{implicits};
455             # my $s = $_[0]->{USER}->{store};
456             map { $implicits->{'isa-thing'}->{$_}++ }
457             (@{$_[2]}, $_[1]); # the types and the ID are declared implicitely
458             }
459            
460             if (ref $_[4]) { # there are inline assocs
461             #warn "test for inlines";
462             foreach (@{$_[4]}) {
463             my $type = $_->[0];
464             my $player = $_->[1];
465             my $store = $_[0]->{USER}->{store};
466             my $templates = $_[0]->{USER}->{templates};
467             #warn "found type $type $player";
468             if ($type eq 'is-subclass-of' || $type eq 'subclasses') {
469             $store->assert ([ undef, # LID
470             undef, # SCOPE
471             'is-subclass-of', # TYPE
472             TM->ASSOC, # KIND
473             [ 'subclass', 'superclass' ], # ROLES
474             [ $_[1], $player ], # PLAYERS
475             undef ] );
476             } elsif ($type eq 'is-a') {
477             $store->assert ([ undef, # LID
478             undef, # SCOPE
479             'isa', # TYPE
480             TM->ASSOC, # KIND
481             [ 'instance', 'class' ], # ROLES
482             [ $_[1], $player ], # PLAYERS
483             undef ] );
484             } elsif ($type eq 'has-a') { # same, but other way round
485             $store->assert ([ undef, # LID
486             undef, # SCOPE
487             'isa', # TYPE
488             TM->ASSOC, # KIND
489             [ 'instance', 'class' ], # ROLES
490             [ $player, $_[1] ], # PLAYERS
491             undef ] );
492             } elsif ($templates->tids ( $type ) &&
493             (my @ts = $templates->match (TM->FORALL, type => $templates->tids ( $type ) ))) {
494             #warn "found templates for $type";
495             warn "duplicate template for '$type' found, taking one" if @ts > 1;
496             my $t = $ts[0]; # I choose one
497              
498             #warn "YYY cloning ($type)";
499              
500             $store->assert ([ undef, # LID
501             undef, # SCOPE
502             $type, # TYPE
503             TM->ASSOC, # KIND
504             [ # ROLES
505             map {
506             my $l = $templates->reified_by ($_);
507             ($l && $l eq LEFT ?
508             $_[1]
509             :
510             ($l && $l eq RIGHT ?
511             $player
512             :
513             $_)
514             )
515             } @{$t->[TM->ROLES]}
516             ],
517             [ # PLAYERS
518             map {
519             my $l = $templates->reified_by ($_);
520             ($l && $l eq LEFT ?
521             $_[1]
522             :
523             ($l && $l eq RIGHT ?
524             $player
525             :
526             $_)
527             )
528             } @{$t->[TM->PLAYERS]}
529             ],
530             undef ] );
531             } else {
532             die "unknown association type '$type' in inlined association";
533             }
534             }
535             }
536             }
537             characteristics_indication
538             {
539             #warn "char/ind in topic: ".Dumper $_[7];
540             my $id = $_[1];
541             # add assertions for every characteristic
542             $_[0]->{USER}->{store}->assert ( map {[ undef, # LID
543             $_->[1], # SCOPE
544             $_->[2] || $TM::CharInfo[$_->[0]]->[0], # TYPE
545             $_->[0], # KIND
546             [ 'thing', $TM::CharInfo[$_->[0]]->[1] ], # ROLES
547             [ $id, $_->[3] ], # PLAYERS
548             undef ] }
549             @{$_[7]->[0]} );
550              
551             map { $store->internalize ($id => $_ ) } @{$_[7]->[1]}; # add the subject indicators
552              
553             { # memorize basename types and scopes as implicitely defined
554             my $implicits = $_[0]->{USER}->{implicits};
555             map { $implicits->{'isa-scope'}->{$_}++ }
556             map { $_->[1] } grep ($_->[1], @{$_[7]->[0]}); # get the bloody scopes and tuck them away
557              
558             map { $implicits->{'subclasses'}->{ $TM::CharInfo[$_->[0]]->[0] }->{$_->[2]}++ }
559             grep ($_->[2], @{$_[7]->[0]}); # get all the characteristics with types
560              
561             #warn "implicits then ".Dumper $implicits;
562             }
563             }
564             ;
565              
566             reification_indication : # empty
567             | REIFIES ID { [ 1, $_[2] ] } # 0, 1, 2 are just local encoding, nothing relevant
568             | ISREIFIED ID { [ 0, $_[2] ] }
569             | ISINDICATEDBY ID { [ 2, $_[2] ] }
570             ;
571              
572             types : { [] } # empty
573             | types type { push @{$_[1]}, @{$_[2]}; $_[1] }
574             ;
575              
576             xtype : ISA ID { [ $_[2] ] }
577             | LPAREN ids RPAREN { $_[2] }
578             ;
579              
580             characteristics_indication : # empty
581             | characteristics_indication characteristic_indication
582             { push @{$_[1]->[ ref($_[2]) eq 'ARRAY' ? 0 : 1 ]}, $_[2]; $_[1] }
583             ; # do not tell me this is not cryptic, it fast, though
584             # if we get a characteristic back, then it is a list ref, then we add it to $_[1]->[0]
585             # if we get a subject indication back, then it is a scalar, so we add it to $_[1]->[1]
586             xcharacteristic_indication : characteristic
587             | indication
588             ;
589              
590             indication : SIN { $_[0]->{USER}->{string} ||= "\n" } string { $_[3] } # TODO: replace with ID?
591             ;
592              
593              
594             class : BN { TM->KIND_BN }
595             | OC { TM->KIND_OC }
596             | IN { TM->KIND_IN }
597             ;
598              
599             char_type : # empty
600             | assoc_type
601             ;
602              
603             assoc_type : LPAREN ID RPAREN { $_[2] }
604             ;
605              
606              
607             inline_assocs : # empty
608             | inline_assocs inline_assoc { push @{$_[1]}, $_[2]; $_[1] }
609             ;
610              
611             inline_assoc : ID ID { [ $_[1], $_[2] ] }
612             ;
613              
614             template_definition : LBRACKET
615             { ($_[0]->{USER}->{templates}, $_[0]->{USER}->{store}) = ($_[0]->{USER}->{store}, $_[0]->{USER}->{templates}); }
616             # flag that we are inside a template
617             association_definition
618             { ($_[0]->{USER}->{templates}, $_[0]->{USER}->{store}) = ($_[0]->{USER}->{store}, $_[0]->{USER}->{templates}); }
619             #RBRACKET # consumed by members already
620             ;
621              
622             association_definition : LPAREN ID RPAREN scope reification_indication EOL
623             association_members
624             {
625             ##warn "members ".Dumper $_[5];
626             ## ??? TODO SCOPE ????
627             my (@roles, @players);
628             foreach my $m (@{$_[7]}) { # one member
629             my $role = shift @$m; # first is role
630            
631             while (@$m) {
632             push @roles, $role; # roles repeat for every player
633             my $player = shift @$m;
634             push @players, $player;
635             }
636             }
637             my ($a) = $_[0]->{USER}->{store}->assert ( [ undef, $_[4], $_[2], TM->ASSOC, \@roles, \@players, undef ] );
638             ##warn "templates" .Dumper $_[0]->{USER}->{store};
639             { # reification
640             my $ms = $_[0]->{USER}->{store};
641             if (ref $_[5]) {
642             if ($_[5]->[0] == 1) { # 1 = REIFIES, 0 = IS-REIFIED
643             # (assoc) reifies http://.... means
644             # 1) the assoc will be addes as thing (is done already)
645             # 2) the http:// will be used as one subject indicator
646             die "reifier of association must be a URI" unless $_[5]->[1] =~ /^\w+:.+/;
647             $ms->internalize ($a->[TM::LID], $_[5]->[1]);
648             } elsif ($_[5]->[0] == 0) { # something reifies this assoc
649             # (assoc) is-reified-by xxx means
650             # 1) assoc is added as thing (is done already)
651             # 2) the local identifier is added as thing with the abs URL of the assoc as subject address
652             die "reifier must be local identifier" unless $_[5]->[1] =~ /^\w+$/;
653             $ms->internalize ($_[5]->[1] => $a->[TM::LID]);
654             } else { # this would be 'indication' but we do not want that here
655             die "indication for association are undefined";
656             }
657             }
658             }
659              
660             { # memorize that association type subclasses association
661             # my $implicits = $_[0]->{USER}->{implicits};
662              
663             # implicit $implicits->{'subclasses'}->{'association'}->{$_[2]}++;
664             $_[0]->{USER}->{implicits}->{'isa-scope'}->{$_[4]}++ if $_[4];
665             }
666             }
667             ;
668              
669             association_members : member { [ $_[1] ] }
670             | association_members member { push @{$_[1]}, $_[2]; $_[1] }
671             ;
672              
673             member : ID COLON ids1 eom { [ $_[1], @{$_[3]} ] }
674             ;
675              
676             eom : EOL # normal assoc
677             | RBRACKET EOL # in case we are inside a template
678             ;
679              
680             ids1 : ids ID { push @{$_[1]}, $_[2]; $_[1] }
681             ;
682              
683             ids : { [] } # empty
684             | ids ID { push @{$_[1]}, $_[2]; $_[1] }
685             ;
686              
687             string : STRING EOL { die "empty string in characteristics" unless $_[1]; \$_[1] }
688             ;
689              
690             %%
691              
692             sub _Error {
693 11     11   250 die "Syntax error: Found ".$_[0]->YYCurtok." but expected ".join (' or ', $_[0]->YYExpect);
694             }
695              
696             sub _Lexer {
697 1224     1224   67772 my $parser = shift;
698 1224         3552 my $refINPUT = \$parser->YYData->{INPUT};
699              
700             # study $$refINPUT;
701              
702 1224 100       8392 $$refINPUT or return ('', undef); # this is the end of the world, as we know it
703 1162         4025 $$refINPUT =~ s/^[ \t]+//o;
704              
705             #warn "lexer ($parser->{USER}->{string}):>>>".$parser->YYData->{INPUT};
706              
707 1162 100       3813 $$refINPUT =~ s/^\n\n//so and return ('DOT', undef);
708 1036 100       2290 $$refINPUT =~ s/^\n$//so and return ('DOT', undef);
709 1008 100       1988 $$refINPUT =~ s/^\.//so and return ('DOT', undef);
710 1007 100       2111 $$refINPUT =~ s/^\~//so and return ('TILDE', undef);
711 999 100       2089 $$refINPUT =~ s/^=//o and return ('EQUAL', undef);
712 993 100       2864 $$refINPUT =~ s/^://o and return ('COLON', undef);
713 859 100       1881 $$refINPUT =~ s/^,\s*(which|who)\b//o and return ('DOWNCOMMA', undef);
714 856 100       3299 $$refINPUT =~ s/^,(?!\s*(which|who)\b)//o and return ('COMMA', undef);
715              
716 848 100       2125 $$refINPUT =~ s/^is-?a\b//o and return ('ISA', undef);
717             # $$refINPUT =~ s/^has-?a\b//o and return ('TED', 'hasa');
718 806 100       1659 $$refINPUT =~ s/^subclasses\b//o and return ('SUBCL', undef);
719              
720 801 100       1692 $$refINPUT =~ s/^has\b//o and return ('HAS', undef);
721              
722 787 100       2061 unless ($parser->{USER}->{assoc}) { # in topic context this corresponds to HAS
723 654 100       2402 $$refINPUT =~ s/^\n\s*(?=\w+\s*[:<@]\s)//so and return ('HAS', undef); # positive look-ahead for things like bn :
724             }
725              
726 716 50       1505 $$refINPUT =~ s/^(which|who)\b//o and return ('WHICH', undef);
727 716 100       1604 $$refINPUT =~ s/^and(\s+(which|who))?\b//so and return ('WHICH', undef); # (can go over lines)
728              
729              
730 707 100       2258 $$refINPUT =~ s/^\n//so and return ('EOL', undef);
731              
732 596 50       1178 $$refINPUT =~ s/^{//so and return ('BRA', undef);
733 596 50       1207 $$refINPUT =~ s/^}//so and return ('KET', undef);
734 596 100       3536 $$refINPUT =~ s/^\(//so and return ('LPAREN', undef);
735 585 100       1399 $$refINPUT =~ s/^\)//so and return ('RPAREN', undef);
736              
737 574 100       1408 $$refINPUT =~ s/^<
738 544 100       1886 $$refINPUT =~ s/^
739              
740 534 50       1033 $$refINPUT =~ s/^>>//o and return ('ISREIFIED', undef);
741              
742              
743 534 100       1120 $$refINPUT =~ s/^\*//o and return ('WILDCARD', undef);
744              
745 527 100 100     1247 $$refINPUT =~ s/^(\d{4}-\d{1,2}-\d{1,2})(T(\d{1,2}):(\d{2}))?//o
      100        
746             and return ('DATE', sprintf "urn:x-date:%s:%02d:%02d", $1, $3 || 0, $4 || 0); # is a date
747              
748 523 100       1393 $$refINPUT =~ s/^bn\b//o and return ('ID', "name");
749 504 100       1122 $$refINPUT =~ s/^oc\b//o and return ('ID', "occurrence");
750 491 100       1101 $$refINPUT =~ s/^in\b//o and return ('ID', "occurrence");
751              
752 478 100       1453 if ($parser->{USER}->{value}) { # parser said we should expect a value now
753             ##warn "expect value >>".$$refINPUT."<<";
754 91 100 50     390 $$refINPUT =~ s/^\"{3}(.*?)\"{3}(?=\n)//so and
755             # (warn "returning multi $1" or 1) and
756             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1)));
757 83 100 50     451 $$refINPUT =~ s/^\"(.*?)\"(^^(\S+))?//o and
758             # (warn "returning simlg $1" or 1) and
759             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1, $3)));
760 60 50 0     168 $$refINPUT =~ s/^(\d+\.\d+)//o and
761             # (warn "returning float $1" or 1) and
762             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1, TM::Literal->DECIMAL)));
763 60 100 50     4313 $$refINPUT =~ s/^(\d+)//o and
764             # (warn "returning int $1" or 1) and
765             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1, TM::Literal->INTEGER)));
766 59 100 50     313 $$refINPUT =~ s/^(\w+:\S+)//o and
767             # (warn "returning uri $1" or 1) and
768             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1, TM::Literal->URI)));
769 48 50 50     617 $$refINPUT =~ s/^(.+?)(?=\s*\n)//o and
770             # (warn "returning unquo $1" or 1) and
771             (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1)));
772              
773             ## (warn "returning $1" or 1) and
774             ## (undef $parser->{USER}->{value} or return ('VALUE', new TM::Literal ($1)));
775             ##warn "no string";
776             }
777              
778             ## unfortunately, this does not what I want:
779             ## $$refINPUT =~ s/^([A-Za-z][A-Za-z0-9_-]*)(?!:)//o and return ('ID', $1); # negative look-ahead
780             ## tricky optimization: don't ask
781 387         455 my $aux; # need this to store identifier/uri prefix temporarily (optimization)
782             my $aux2; # need this to store ontology URL, if there is one
783 387 100 66     4851 $$refINPUT =~ s/^([A-Za-z][.A-Za-z0-9_-]*)//o and $aux = $1 # save this for later
    100 100        
784             and $$refINPUT !~ /^:[\w\/]/
785             and return (_is_template ($parser->{USER}->{store},
786             $aux)
787             ? 'TED' : 'ID', $aux);
788              
789 67 100       449 $$refINPUT =~ s/^(:([^\s\)\(\]\[]+))//o and return ('URI', ( $aux2 = _is_ontology ($parser->{USER}->{store},
    100          
790             $parser->{USER}->{prefixes},
791             $aux)) ? $aux2."#$2" : $aux.$1); # is a URL/URN actually
792              
793 16 100       100 $$refINPUT =~ s/^@//so and return ('AT', undef);
794              
795              
796 7 100       51 $$refINPUT =~ s/^%include\s+(.*?)(?=\n)//so and return ('INCLUDE', $1); # positive look-ahead
797 5 100       27 $$refINPUT =~ s/^%log\s+(.*?)(?=\n)//so and return ('LOG', $1); # positive look-ahead
798 4 100       25 $$refINPUT =~ s/^%cancel(?=\n)//so and return ('CANCEL', $1); # positive look-ahead
799 3 100       38 $$refINPUT =~ s/^%version\s+(\d+\.\d+)(?=\n)//so and return ('VERSION', $1); # positive look-ahead
800              
801 1 50       17 $$refINPUT =~ s/^%encoding\s+(.*?)(?=\n)//so and return ('ENCODING', $1); # positive look-ahead
802              
803              
804             # $$refINPUT =~ s/^\[//so and return ('LBRACKET', undef);
805             # $$refINPUT =~ s/^\]//so and return ('RBRACKET', undef);
806              
807 0 0       0 $$refINPUT =~ s/^(.)//so and return ($1, $1); # should not be an issue except on error
808             }
809              
810             sub _is_template {
811 320     320   458 my $store = shift;
812 320         411 my $id = shift;
813              
814 320 100       1052 my $t = $store->tids ($id) or return undef;
815 77         231 return $store->is_a ($t, $store->tids (\ TEMPLATE));
816             }
817              
818             sub _is_ontology {
819 51     51   84 my $store = shift;
820 51         54 my $prefixes = shift;
821 51         74 my $prefix = shift;
822              
823             #warn "texting prefix '$prefix' on ".Dumper $prefixes;
824 51 100       146 return $prefixes->{$prefix} if $prefixes->{$prefix}; # cache
825              
826 48 100       123 if ($prefix eq 'astma') { # this is one predefined prefix
    100          
827 10         34 $prefixes->{$prefix} = ASTMA;
828             } elsif ($prefix eq 'xsd') { # this is the other predefined prefix
829 1         4 $prefixes->{$prefix} = XSD;
830             } else {
831 37         113 my $p = $store->tids ($prefix);
832 37 100 100     122 if ($p && $store->is_a ($p, $store->tids (\ ONTOLOGY))) { # is the topic an instance of astma:ontology?
833 2 100       9 $prefixes->{$prefix} =
834             $store->toplet ($store->tids ($prefix))->[TM->INDICATORS]->[0] # then take its subject indicator as expanded URI
835             or die "no subject indicator for '$prefix' provided"; # if there is none, complain
836             }
837             }
838             #warn "prefixes now".Dumper $prefixes;
839 47         325 return $prefixes->{$prefix};
840             }
841              
842             sub parse {
843 82     82 0 431 my $self = shift;
844 82         384 $self->YYData->{INPUT} = shift;
845              
846             #warn "parse";
847              
848 82         781 $self->YYData->{INPUT} =~ s/\r/\n/sg;
849 82         652 $self->YYData->{INPUT} =~ s/(?
850 82         632 $self->YYData->{INPUT} =~ s/ \+{3} /\n/g; # replace _+++_ with \n
851 82         624 $self->YYData->{INPUT} =~ s/\+{4}/+++/g; # stuffed ++++ cleanout
852 82         559 $self->YYData->{INPUT} =~ s/^\#.*?\n/\n/mg; # # at there start of every line -> gone
853 82         677 $self->YYData->{INPUT} =~ s/\s+\#.*?\n/\n/mg; # anything which starts with #, all blanks are ignored
854 82         609 $self->YYData->{INPUT} =~ s/\n\n\n+/\n\n/sg;
855 82         565 $self->YYData->{INPUT} =~ s/\n\s+\n+/\n\n/sg; # trimm lines with blanks only
856              
857             # we not only capture what is said EXPLICITELY in the map, we also collect implicit knowledge
858             # we could add this immediately into the map at parsing, but it would slow the process down and
859             # it would probably duplicate/complicate things
860 82         1153 $self->{USER}->{implicits} = {
861             'isa-thing' => undef, # just let them spring into existence
862             'isa-scope' => undef, # just let them spring into existence
863             'subclasses' => undef
864             };
865             # $self->{USER}->{topic_count} = 0;
866              
867             # $self->{USER}->{templates} = new TM (psis => undef, baseuri => $self->{USER}->{store}->baseuri);
868 82         324 $self->{USER}->{prefixes} = {};
869              
870 82         158 eval {
871 82         504 $self->YYParse ( yylex => \&_Lexer, yyerror => \&_Error); #, yydebug => 0x01 );
872 82 100       3354 }; if ($@ =~ /^Cancelled/) {
    100          
873 1         32 warn $@; # de-escalate Cancelling to warning
874             } elsif ($@) {
875 19         4388 die $@; # otherwise re-raise the exception
876             }
877             #warn "in parse end ".Dumper $self->{USER}->{implicits};
878             { # resolving implicit stuff
879 63         89 my $implicits = $self->{USER}->{implicits};
  63         172  
880 63         148 my $store = $self->{USER}->{store};
881              
882             { # all super/subclasses
883 63         79 foreach my $superclass (keys %{$implicits->{'subclasses'}}) {
  63         108  
  63         310  
884 0         0 $store->assert ( map {
885 0         0 [ undef, undef, 'is-subclass-of', TM->ASSOC, [ 'superclass', 'subclass' ], [ $superclass, $_ ] ]
886 0         0 } keys %{$implicits->{'subclasses'}->{$superclass}});
887             }
888             }
889             { # all things in isa-things are THINGS, simply add them
890 63         113 $store->internalize (map { $_ => undef } keys %{$implicits->{'isa-thing'}});
  63         135  
  0         0  
  63         303  
891             }
892             { # establishing the scoping topics
893 63         106 $store->assert (map {
  1         9  
894 63         345 [ undef, undef, 'isa', TM->ASSOC, [ 'class', 'instance' ], [ 'scope', $_ ] ]
895 63         88 } keys %{$implicits->{'isa-scope'}});
896             }
897 63         201 $store->externalize ( $store->instances ($store->tids (\ TEMPLATE)) ); # "removing templates now";
898             }
899 63         408 return $self->{USER}->{store};
900             }
901              
902             #my $f = new TM::AsTMa::Fact;
903             #$f->Run;