activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,443 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler
4
-
5
- # An Operation is a binary or ternary fact type involving an operator,
6
- # a result, and one or two operands.
7
- # Viewed as a result, it behaves like a Reference with a nested Clause.
8
- # Viewed as a fact type, it behaves like a Clause.
9
- #
10
- # The only exception here is an equality comparison, where it may
11
- # turn out that the equality is merely a projection. In this case
12
- # the Operation is dropped from the clauses and is replaced by the
13
- # projected operand.
14
- #
15
- # Each operand may be a Literal, a Reference, or another Operation,
16
- # so we need to recurse down the tree to build the query.
17
- #
18
- class Operation
19
- # Reference (in)compatibility:
20
- [ :term, :leading_adjective, :trailing_adjective, :role_name, :quantifier,
21
- :value_constraint, :embedded_presence_constraint, :literal
22
- ].each do |s|
23
- define_method(s) { raise "Unexpected call to Operation\##{s}" }
24
- define_method(:"#{s}=") { raise "Unexpected call to Operation\##{s}=" }
25
- end
26
- def role_name; nil; end
27
- def leading_adjective; nil; end
28
- def trailing_adjective; nil; end
29
- def value_constraint; nil; end
30
- def literal; nil; end
31
- def side_effects; nil; end
32
- attr_accessor :player # What ObjectType does the Binding denote
33
- attr_accessor :binding # What Binding for that ObjectType
34
- attr_accessor :clause # What clause does the result participate in?
35
- attr_accessor :role # Which Role of this ObjectType
36
- attr_accessor :role_ref # Which RoleRef to that Role
37
- attr_accessor :certainty # nil, true, false -> maybe, definitely, not
38
- def nested_clauses; @nested_clauses ||= [self]; end
39
- def clause; self; end
40
- def objectification_of; @fact_type; end
41
- # Clause (in)compatibility:
42
- [ :phrases, :qualifiers, :context_note, :reading, :role_sequence, :fact
43
- ].each do |s|
44
- define_method(s) { raise "Unexpected call to Operation\##{s}" }
45
- define_method(:"#{s}=") { raise "Unexpected call to Operation\##{s}=" }
46
- end
47
- def conjunction; nil; end
48
- attr_reader :fact_type
49
- def objectified_as; self; end # The Reference which objectified this fact type
50
-
51
- def initialize
52
- @certainty = true # Assume it's definite
53
- end
54
-
55
- def operands context = nil
56
- raise "REVISIT: Implement operand enumeration in the operator subclass #{self.class.name}"
57
- end
58
-
59
- def identify_players_with_role_name context
60
- # Just recurse, there's no way (yet: REVISIT?) to add a role name to the result of an expression
61
- refs.each { |o|
62
- o.identify_players_with_role_name(context)
63
- }
64
- # As yet, an operation cannot have a role name:
65
- # identify_player context if role_name
66
- end
67
-
68
- def identify_other_players context
69
- # Just recurse, there's no way (yet: REVISIT?) to add a role name to the result of an expression
70
- refs.each { |o|
71
- o.identify_other_players(context)
72
- }
73
- identify_player context
74
- end
75
-
76
- def bind context
77
- refs.each do |o|
78
- o.bind context
79
- end
80
- name = result_type_name(context)
81
- @player = result_value_type(context, name)
82
- key = "#{name} #{object_id}" # Every Operation result is a unique Binding
83
- @binding = (context.bindings[key] ||= Binding.new(@player))
84
- @binding.refs << self
85
- @binding
86
- end
87
-
88
- def result_type_name(context)
89
- raise "REVISIT: Implement result_type_name in the #{self.class.name} subclass"
90
- end
91
-
92
- def result_value_type(context, name)
93
- vocabulary = context.vocabulary
94
- constellation = vocabulary.constellation
95
- vocabulary.valid_value_type_name(name) ||
96
- constellation.ValueType(vocabulary, name, :concept => :new)
97
- end
98
-
99
- def is_naked_object_type
100
- false # All Operations are non-naked
101
- end
102
-
103
- def match_existing_fact_type context
104
- opnds = refs
105
- result_ref = Reference.new(@binding.player.name)
106
- result_ref.player = @binding.player
107
- result_ref.binding = @binding
108
- @binding.refs << result_ref
109
- clause_ast = Clause.new(
110
- [result_ref, '='] +
111
- (opnds.size > 1 ? [opnds[0]] : []) +
112
- [operator, opnds[-1]]
113
- )
114
-
115
- # REVISIT: All operands must be value-types or simply-identified Entity Types.
116
-
117
- # REVISIT: We should auto-create steps from Entity Types to an identifying ValueType
118
- # REVISIT: We should traverse up the supertype of ValueTypes to find a DataType
119
- @fact_type = clause_ast.match_existing_fact_type(context, :exact_type => true)
120
- if clause.certainty == false
121
- raise "Negated fact types in expressions are not yet supported: #{clause.inspect}"
122
- end
123
- return @fact_type if @fact_type
124
-
125
- @fact_type = clause_ast.make_fact_type context.vocabulary
126
- reading = clause_ast.make_reading context.vocabulary, @fact_type
127
- rrs = reading.role_sequence.all_role_ref_in_order
128
- opnds[0].role_ref = rrs[0]
129
- opnds[-1].role_ref = rrs[-1]
130
- opnds.each do |opnd|
131
- next unless opnd.is_a?(Operation)
132
- opnd.match_existing_fact_type context
133
- if opnd.certainty == false
134
- raise "Negated fact types in expressions are not yet supported: #{opnd.inspect}"
135
- end
136
- end
137
- @fact_type
138
- end
139
-
140
- def is_equality_comparison
141
- false
142
- end
143
-
144
- def operator
145
- raise "REVISIT: Implement operator access in the operator subclass #{self.class.name}"
146
- end
147
-
148
- end
149
-
150
- class Comparison < Operation
151
- attr_accessor :operator, :e1, :e2, :qualifiers, :conjunction
152
-
153
- def initialize operator, e1, e2, certainty = true
154
- @operator, @e1, @e2, @certainty, @qualifiers = operator, e1, e2, certainty, []
155
- end
156
-
157
- def refs
158
- [@e1, @e2]
159
- end
160
-
161
- def bind context
162
- refs.each do |o|
163
- o.bind context
164
- end
165
-
166
- # REVISIT: Return the projected binding instead:
167
- return @result = nil if @projection
168
-
169
- name = 'Boolean'
170
- @player = result_value_type(context, name)
171
- key = "#{name} #{object_id}" # Every Comparison result is a unique Binding
172
- @binding = (context.bindings[key] ||= Binding.new(@player))
173
- @binding.refs << self
174
- @binding
175
- end
176
-
177
- def result_type_name(context)
178
- "COMPARE#{operator}<#{[@e1,@e2].map{|e| e.player.name}*' WITH '})>"
179
- end
180
-
181
- def is_equality_comparison
182
- @operator == '='
183
- end
184
-
185
- def identify_player context
186
- @player || begin
187
- if @projection
188
- raise "REVISIT: The player is the projected expression"
189
- end
190
- v = context.vocabulary
191
- @boolean ||=
192
- v.constellation.ValueType[[[v.name], 'Boolean']] ||
193
- v.constellation.ValueType(v, 'Boolean', :concept => :new)
194
- @player = @boolean
195
- end
196
- end
197
-
198
- =begin
199
- def project lr
200
- @projection = lr
201
- projected_rr = lr == :left ? @e2 : @e1
202
- true
203
- end
204
- =end
205
-
206
- def inspect; to_s; end
207
-
208
- def to_s
209
- "COMPARE#{
210
- operator
211
- }(#{
212
- case @certainty
213
- when nil; 'maybe '
214
- when false; 'negated '
215
- # else 'definitely '
216
- end
217
- }#{
218
- e1.to_s
219
- } WITH #{
220
- e2.to_s
221
- }#{
222
- @qualifiers.empty? ? '' : ', ['+@qualifiers*', '+']'
223
- })"
224
- end
225
- end
226
-
227
- class Sum < Operation
228
- attr_accessor :terms
229
- def initialize *terms
230
- @terms = terms
231
- end
232
-
233
- def refs
234
- @terms
235
- end
236
-
237
- def operator
238
- '+'
239
- end
240
-
241
- def identify_player context
242
- @player || begin
243
- # The players in the @terms have already been identified
244
- # REVISIT: Check compliance of all units in @terms, and apply conversions where necessary
245
- # REVISIT: The type of this result should be derived from type promotion rules. Here, we take the left-most.
246
- # REVISIT: We should define a subtype of the result type here, and apply the units to it.
247
- v = context.vocabulary
248
- @player = @terms[0].player
249
- @player
250
- end
251
- end
252
-
253
- def result_type_name(context)
254
- "SUM_OF<#{ @terms.map{|f| f.player.name}*', ' }>"
255
- end
256
-
257
- =begin
258
- def result_value_type(context, name)
259
- # REVISIT: If there are units involved, check compatibility
260
- vt = super
261
- vt
262
- end
263
- =end
264
-
265
- def inspect; to_s; end
266
-
267
- def to_s
268
- 'SUM(' + @terms.map{|term| "#{term.to_s}" } * ' PLUS ' + ')'
269
- end
270
- end
271
-
272
- class Product < Operation
273
- attr_accessor :factors
274
- def initialize *factors
275
- @factors = factors
276
- end
277
-
278
- def refs
279
- @factors
280
- end
281
-
282
- def operator
283
- '*'
284
- end
285
-
286
- def identify_player context
287
- @player || begin
288
- # The players in the @factors have already been identified
289
- # REVISIT: Calculate the units of the result from the units in @factors
290
- # REVISIT: The type of this result should be derived from type promotion rules. Here, we take the left-most.
291
- # REVISIT: We should define a subtype of the result type here, and apply the units to it.
292
- v = context.vocabulary
293
- @player = @factors[0].player
294
- end
295
- end
296
-
297
- def result_type_name(context)
298
- "PRODUCT_OF<#{ @factors.map{|f| f.player.name}*' ' }>"
299
- end
300
-
301
- =begin
302
- def result_value_type(context, name)
303
- vt = super
304
- # REVISIT: If there are units involved, create the result units
305
- vt
306
- end
307
- =end
308
-
309
- def inspect; to_s; end
310
-
311
- def to_s
312
- 'PRODUCT(' + @factors.map{|factor| "#{factor.to_s}" } * ' TIMES ' + ')'
313
- end
314
- end
315
-
316
- class Reciprocal < Operation
317
- attr_accessor :divisor
318
- def initialize divisor
319
- @divisor = divisor
320
- end
321
-
322
- def operator
323
- '1/'
324
- end
325
-
326
- def refs
327
- [@divisor]
328
- end
329
-
330
- def identify_player context
331
- @player || begin
332
- # The player in @divisor has already been identified
333
- # REVISIT: Calculate the units of the result from the units in @divisor
334
- # REVISIT: Do we want integer division?
335
- v = context.vocabulary
336
- @player = v.constellation.ValueType(v, 'Real', :concept => :new)
337
- end
338
- end
339
-
340
- =begin
341
- def result_type_name(context)
342
- raise hell
343
- end
344
- =end
345
-
346
- def inspect; to_s; end
347
-
348
- def to_s
349
- "RECIPROCAL(#{factor.to_s})"
350
- end
351
- end
352
-
353
- class Negate
354
- attr_accessor :term
355
- def initialize term
356
- @term = term
357
- end
358
-
359
- def operator
360
- '0-'
361
- end
362
-
363
- def identify_player context
364
- @player || begin
365
- # The player in @term have already been identified
366
- v = context.vocabulary
367
- @player = @term.player
368
- end
369
- end
370
-
371
- =begin
372
- def result_type_name(context)
373
- raise hell
374
- end
375
- =end
376
-
377
- def inspect; to_s; end
378
-
379
- def to_s
380
- "NEGATIVE(#{term.to_s})"
381
- end
382
- end
383
-
384
- class Literal
385
- attr_accessor :literal, :unit, :role, :role_ref, :clause
386
- attr_reader :objectification_of, :leading_adjective, :trailing_adjective, :value_constraint
387
-
388
- def initialize literal, unit
389
- @literal, @unit = literal, unit
390
- end
391
-
392
- # Stubs:
393
- def role_name; nil; end
394
- def nested_clauses; nil; end
395
-
396
- def inspect; to_s; end
397
-
398
- def to_s
399
- unit ? "(#{@literal.to_s} in #{unit.to_s})" : @literal.to_s
400
- end
401
-
402
- def player
403
- @player
404
- end
405
-
406
- def identify_players_with_role_name(context)
407
- # Nothing to do here, move along
408
- end
409
-
410
- def identify_other_players(context)
411
- identify_player context
412
- end
413
-
414
- def identify_player context
415
- @player || begin
416
- player_name =
417
- case @literal
418
- when String; 'String'
419
- when Float; 'Real'
420
- when Numeric; 'Integer'
421
- when TrueClass, FalseClass; 'Boolean'
422
- end
423
- v = context.vocabulary
424
- @player = v.constellation.ValueType(v, player_name)
425
- end
426
- end
427
-
428
- def bind context
429
- @binding || begin
430
- key = "#{@player.name} #{@literal}"
431
- @binding = (context.bindings[key] ||= Binding.new(@player))
432
- @binding.refs << self
433
- end
434
- end
435
-
436
- def binding
437
- @binding
438
- end
439
- end
440
-
441
- end
442
- end
443
- end
@@ -1,390 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
-
5
- class Fact < Definition
6
- def initialize clauses, population_name = ''
7
- @clauses = clauses
8
- @population_name = population_name
9
- end
10
-
11
- def compile
12
- @population = @constellation.Population[[@vocabulary.identifying_role_values, @population_name]] ||
13
- @constellation.Population(@vocabulary, @population_name, :concept => :new)
14
-
15
- @context = CompilationContext.new(@vocabulary)
16
- @context.bind @clauses
17
- @context.left_contraction_allowed = true
18
- @clauses.each do |clause|
19
- ft = clause.match_existing_fact_type @context
20
- if clause.certainty == false
21
- raise "Negated fact #{clause.inspect} is not supported"
22
- end
23
- end
24
-
25
- # Figure out the simple existential facts and find fact types:
26
- @bound_facts = []
27
- @unbound_clauses = all_clauses(@clauses).
28
- map do |clause|
29
- bind_literal_or_fact_type clause
30
- end.
31
- compact
32
-
33
- # Because the fact types may include forward references, we must
34
- # process the list repeatedly until we make no further progress.
35
- @pass = 0 # Repeat until we make no more progress:
36
- true while bind_more_facts
37
-
38
- # Any remaining unbound facts are a problem we can bitch about:
39
- complain_incomplete unless @unbound_clauses.empty?
40
-
41
- @bound_facts.uniq # N.B. this includes Instance objects (existential facts)
42
- end
43
-
44
- def bind_literal_or_fact_type clause
45
- # Every bound word (term) in the phrases must have a literal
46
- # OR be bound to an entity type identified by the phrases
47
-
48
- # Any clause that has one binding and no other word is
49
- # either a value instance or a simply-identified entity.
50
- clause.refs.each do |ref|
51
- next unless l = ref.literal # No literal
52
- next if ref.binding.instance # Already bound
53
- player = ref.binding.player
54
- # raise "A literal may not be an objectification" if ref.role_ref.nested_clauses
55
- # raise "Not processing facts involving nested clauses yet" if ref.role_ref
56
- trace :instance_detail, "Making #{player.class.basename} #{player.name} using #{l.inspect}" do
57
- ref.binding.instance = instance_identified_by_literal(player, l)
58
- end
59
- ref
60
- end
61
-
62
- if clause.phrases.size == 1 and (ref = clause.phrases[0]).is_a?(Compiler::Reference)
63
- if ref.nested_clauses
64
- # Assign the objectified fact type as this clause's fact type?
65
- clause.fact_type = ref.player.fact_type
66
- clause
67
- else
68
- # This is an existential fact (like "Name 'foo'", or "Company 'Microsoft'")
69
- nil # Nothing to see here, move along
70
- end
71
- else
72
- raise "Fact Type not found: '#{clause.display}'" unless clause.fact_type
73
- # This instance will be associated with its binding by our caller
74
- clause
75
- end
76
- end
77
-
78
- #
79
- # Try to bind this clause, and return true if it can be completed
80
- #
81
- def bind_clause clause
82
- return true if clause.fact
83
-
84
- # Find the roles of this clause that do not yet have an instance
85
- bare_roles = clause.refs.
86
- select do |ref|
87
- if !ref.binding.instance and ref.literal
88
- ref.binding.instance = instance_identified_by_literal(ref.binding.player, ref.literal)
89
- end
90
-
91
- next false if ref.binding.instance
92
- true
93
- end
94
-
95
- trace :instance_detail, "Considering '#{clause.display}' with "+
96
- (bare_roles.empty? ? "no bare roles" : "bare roles: #{bare_roles.map{|ref| ref.player.name}*", "}") do
97
-
98
- # If all the roles are in place, we can bind the rest of this clause:
99
- return true if bare_roles.size == 0 && bind_complete_fact(clause)
100
-
101
- progress = false
102
- if bare_roles.size == 1 &&
103
- (binding = bare_roles[0].binding) &&
104
- (et = binding.player).is_a?(ActiveFacts::Metamodel::EntityType)
105
- if et.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type == clause.fact_type} &&
106
- bind_entity_if_identifier_ready(clause, et, binding)
107
- progress = true
108
- end
109
- end
110
-
111
- return true if progress
112
- trace :instance_detail, "Delaying until all role players are asserted: #{clause.fact_type.default_reading.inspect}"
113
- nil
114
- end
115
- end
116
-
117
- # Take one pass through the @unbound_clauses, processing (and removing) any that have all pre-requisites
118
- def bind_more_facts
119
- return false unless @unbound_clauses.size > 0
120
- @pass += 1
121
-
122
- progress = false
123
- trace :instance_detail, "Pass #{@pass} with #{@unbound_clauses.size} clauses to consider" do
124
- @unbound_clauses =
125
- @unbound_clauses.select do |clause|
126
- action = bind_clause(clause)
127
- progress = true if action
128
- !action
129
- end
130
- trace :instance_detail, "end of pass, unbound clauses are #{@unbound_clauses.map(&:display)*', '}"
131
- end # debug
132
- progress
133
- end
134
-
135
- # Occasionally we need to search through all the clauses. This builds a flat list
136
- def all_clauses clauses
137
- clauses.map do |clause|
138
- [clause] + clause.refs.map{|vr| vr.nested_clauses ? all_clauses(vr.nested_clauses) : []}
139
- end.flatten.compact
140
- end
141
-
142
- def bind_complete_fact clause
143
- return true unless clause.fact_type # An bare objectification
144
- instances = clause.refs.map{|vr| vr.binding.instance }
145
- trace :instance_detail, "All role players exist for #{clause.display.inspect} exist: #{instances.map{|i| "#{i.verbalise}"}*", "}"
146
-
147
- if e = clause.fact_type.entity_type and
148
- clause.refs[0].binding.instance.object_type == e
149
- fact = clause.refs[0].binding.instance.fact
150
- else
151
- # Check that this fact doesn't already exist
152
- trace :instance_detail, "Searching for existing fact instance"
153
-
154
- fact = clause.fact_type.all_fact.detect do |f|
155
-
156
- # Get the role values of this fact in the order of the clause we just bound
157
- role_values_in_clause_order = f.all_role_value.sort_by do |rv|
158
- clause.reading.role_sequence.all_role_ref.detect{|rr| rr.role == rv.role}.ordinal
159
- end
160
-
161
- # If all this fact's role values are played by the bound instances, it's the same fact
162
- !role_values_in_clause_order.zip(instances).detect{|rv, i| rv.instance != i }
163
- end
164
- end
165
- if fact
166
- clause.fact = fact
167
- trace :instance, "Already known: #{fact.verbalise.inspect}"
168
- else
169
- trace :instance_detail, "Asserting fact of type #{clause.fact_type.default_reading.inspect}"
170
- fact =
171
- clause.fact =
172
- @constellation.Fact(:new, :fact_type => clause.fact_type, :population => @population)
173
- @bound_facts << fact
174
- clause.reading.role_sequence.all_role_ref_in_order.zip(instances).each do |rr, instance|
175
- trace :instance_detail, "Assigning fact role #{instance.object_type.name} to #{instance.value ? instance.value.inspect : instance.verbalise}"
176
- # REVISIT: Any residual adjectives after the fact type matching are lost here.
177
- @constellation.RoleValue(:fact => fact, :instance => instance, :role => rr.role, :population => @population)
178
- end
179
- trace :instance, "Assert #{fact.verbalise.inspect} #{@population.name.size>0 ? " in "+@population.name.inspect : ''}" unless clause.fact_type.entity_type
180
- end
181
-
182
- if !fact.instance && clause.fact_type.entity_type
183
- # Objectified fact type; create the instance
184
- # Create the instance that objectifies this fact. We don't have the binding to assign it to though; that'll happen in our caller
185
- instance =
186
- @constellation.Instance(:new, :object_type => clause.fact_type.entity_type, :fact => fact, :population => @population)
187
- trace :instance, "Assert #{instance.verbalise.inspect}"
188
- @bound_facts << instance
189
- end
190
-
191
- if clause.fact and
192
- clause.objectified_as and
193
- instance = clause.fact.instance and
194
- instance.object_type == clause.objectified_as.binding.player
195
- clause.objectified_as.binding.instance = instance
196
- end
197
-
198
- true
199
- end
200
-
201
- # If we have one bare role (no literal or instance) played by an entity type,
202
- # and the bound fact type participates in the identifier, we might now be able
203
- # to create the entity instance.
204
- def bind_entity_if_identifier_ready clause, entity_type, binding
205
- # Check this instance doesn't already exist already:
206
- identifying_binding = (clause.refs.map{|vr| vr.binding}-[binding])[0]
207
- return false unless identifying_binding # This happens when we have a bare objectification
208
- identifying_instance = identifying_binding.instance
209
- preferred_identifier = entity_type.preferred_identifier
210
- role_count = preferred_identifier.role_sequence.all_role_ref.size
211
-
212
- trace :instance, "A #{binding.player.name} is #{role_count > 1 ? 'partly ':''}identified in #{clause.inspect}"
213
-
214
- identifying_role_ref = preferred_identifier.role_sequence.all_role_ref.detect { |rr|
215
- rr.role.fact_type == clause.fact_type && rr.role.object_type == identifying_binding.player
216
- }
217
- unless identifying_role_ref
218
- # This should never happen; we already bound all refs
219
- trace :instance, "Failed to find a #{identifying_instance.object_type.name}"
220
- return false # We can't do this yet
221
- end
222
- role_value = identifying_instance.all_role_value.detect do |rv|
223
- rv.fact.fact_type == identifying_role_ref.role.fact_type
224
- end
225
- if role_value && role_count == 1
226
- instance = (role_value.fact.all_role_value.to_a-[role_value])[0].instance
227
- trace :instance, "Existential fact already known: #{instance.verbalise.inspect}"
228
- binding.instance = instance
229
- return true # Done with this clause
230
- end
231
-
232
- pi_role_refs = preferred_identifier.role_sequence.all_role_ref
233
- # For each pi role, we have to find the fact clause, which contains the binding we need.
234
- # Then we have to create an instance of each fact
235
- identifiers =
236
- pi_role_refs.map do |rr|
237
- # Find a clause that provides the identifying_ref for this player:
238
- identifying_clause = all_clauses(@clauses).detect do |clause|
239
- rr.role.fact_type == clause.fact_type &&
240
- clause.refs.detect{|vr| vr.binding == binding}
241
- end
242
- return false unless identifying_clause
243
- identifying_ref = identifying_clause.refs.select{|ref| ref.binding != binding}[0]
244
- identifying_binding = identifying_ref ? identifying_ref.binding : nil
245
- identifying_instance = identifying_binding.instance
246
-
247
- [rr, identifying_clause, identifying_binding, identifying_instance]
248
- end
249
- if identifiers.detect{ |i| !i[3] } # Not all required facts are bound yet
250
- trace :instance, "Can't go through with creating #{binding.player.name}; not all the identifying facts are in"
251
- return false
252
- end
253
-
254
- instance = @constellation.Instance(:new, :object_type => entity_type, :population => @population)
255
- binding.instance = instance
256
- @bound_facts << instance
257
- identifiers.each do |rr, identifying_clause, identifying_binding, identifying_instance|
258
- # This clause provides the identifying literal for the entity_type
259
- id_fact =
260
- identifying_clause.fact =
261
- @constellation.Fact(:new, :fact_type => rr.role.fact_type, :population => @population)
262
- @bound_facts << id_fact
263
- role = (rr.role.fact_type.all_role.to_a-[rr.role])[0]
264
- @constellation.RoleValue(:instance => instance, :fact => id_fact, :population => @population, :role => role)
265
- @constellation.RoleValue(:instance => identifying_instance, :fact => id_fact, :role => rr.role, :population => @population)
266
- trace :instance, "Assert #{id_fact.verbalise.inspect} (existential) #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
267
- end
268
- trace :instance, "Assert #{instance.verbalise.inspect} #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
269
-
270
- true # Done with this clause
271
- end
272
-
273
- def instance_identified_by_literal object_type, literal
274
- if object_type.is_a?(ActiveFacts::Metamodel::EntityType)
275
- entity_identified_by_literal object_type, literal
276
- else
277
- trace :instance_detail, "Assert Value #{object_type.name} #{literal.inspect}" do
278
- is_literal_string = literal.literal.is_a?(String)
279
- # REVISIT: Check for subtypes and supertypes also, and promote type if necessary
280
- instance = object_type.all_instance.detect do |i|
281
- #instance = @constellation.Instance.detect do |key, i|
282
- # REVISIT: And same unit
283
- trace :instance_detail2, "Comparing #{i.value.literal.inspect} to #{literal.literal.to_s.inspect}"
284
- i.population == @population &&
285
- i.value &&
286
- i.value.literal.inspect == literal.literal.to_s.inspect &&
287
- i.value.is_literal_string == is_literal_string
288
- end
289
- #instance = object_type.all_instance.detect { |instance|
290
- # instance.population == @population && instance.value == literal
291
- #}
292
- if instance
293
- trace :instance, "Instance already known: #{instance.verbalise.inspect}"
294
- else
295
- instance = @constellation.Instance(:new)
296
- instance.object_type = object_type
297
- instance.population = @population
298
- instance.value = [literal.to_s, is_literal_string, nil]
299
- trace :instance, "Assert #{instance.verbalise.inspect} #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
300
- @bound_facts << instance
301
- end
302
- instance
303
- end
304
- end
305
- end
306
-
307
- def entity_identified_by_literal object_type, literal
308
- # A literal that identifies an entity type means the entity type has only one identifying role
309
- # That role is played either by a value type, or by another similarly single-identified entity type
310
- trace :instance_detail, "Assert Entity #{object_type.name} identified by '#{literal}'" do
311
- identifying_role_refs = object_type.preferred_identifier.role_sequence.all_role_ref
312
- raise "Single literal cannot satisfy multiple identifying roles for #{object_type.name}" if identifying_role_refs.size > 1
313
- role = identifying_role_refs.single.role
314
- # This instance has no binding; the binding is of the entity type not the identifying value type
315
- identifying_instance = instance_identified_by_literal role.object_type, literal
316
- existing_instance = nil
317
- instance_rv = identifying_instance.all_role_value.detect { |rv|
318
- next false unless rv.population == @population # Not this population
319
- next false unless rv.fact.fact_type == role.fact_type # Not this fact type
320
- other_role_value = (rv.fact.all_role_value-[rv])[0]
321
- existing_instance = other_role_value.instance
322
- other_role_value.instance.object_type == object_type # Is it this object_type?
323
- }
324
- if instance_rv
325
- instance = existing_instance
326
- trace :instance, "Already known: #{instance.verbalise.inspect}"
327
- else
328
- # This fact has no clause.
329
- trace :instance_detail, "Creating implicit existential fact #{role.fact_type.default_reading}"
330
- fact = @constellation.Fact(:new, :fact_type => role.fact_type, :population => @population)
331
- @bound_facts << fact
332
- # This instance will be associated with its binding by our caller
333
- instance = @constellation.Instance(:new, :object_type => object_type, :population => @population)
334
- trace :instance_detail, "Creating Entity #{object_type.name} identified by '#{literal}' #{@population.name.size>0 ? " in "+@population.name.inspect : ''}"
335
- @bound_facts << instance
336
- # The identifying fact type has two roles; create both role instances:
337
- @constellation.RoleValue(:instance => identifying_instance, :fact => fact, :population => @population, :role => role)
338
- @constellation.RoleValue(:instance => instance, :fact => fact, :population => @population, :role => (role.fact_type.all_role-[role])[0])
339
- trace :instance, "Assert #{instance.verbalise.inspect}"
340
- end
341
- instance
342
- end
343
- end
344
-
345
- def complain_incomplete
346
- if @unbound_clauses.size > 0
347
- # Provide a readable description of the problem here, by showing each binding with no instance
348
- missing_bindings = @unbound_clauses.
349
- map do |clause|
350
- clause.refs.
351
- select do |refs|
352
- !refs.binding.instance
353
- end.
354
- map do |ref|
355
- ref.binding
356
- end
357
- end.
358
- flatten.
359
- uniq
360
-
361
- raise "Not enough facts are given to identify #{
362
- missing_bindings.
363
- sort_by{|b| b.key}.
364
- map do |b|
365
- player_identifier =
366
- if b.player.is_a?(ActiveFacts::Metamodel::EntityType)
367
- "lacking " +
368
- b.player.preferred_identifier.role_sequence.all_role_ref.map do |rr|
369
- [ rr.leading_adjective, rr.role.role_name || rr.role.object_type.name, rr.trailing_adjective ].compact*" "
370
- end*", "
371
- else
372
- "needs a value"
373
- end
374
- [
375
- b.refs[0].leading_adjective, b.player.name, b.refs[0].trailing_adjective
376
- ].compact*" " +
377
- " (#{player_identifier})"
378
- end*" or "
379
- }"
380
- end
381
- end
382
-
383
- def to_s
384
- super+@clauses.map(&:to_s)*', '
385
- end
386
-
387
- end
388
- end
389
- end
390
- end