activefacts 0.8.9 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemtest +0 -0
- data/Manifest.txt +28 -33
- data/Rakefile +11 -12
- data/bin/cql +90 -46
- data/examples/CQL/Blog.cql +2 -1
- data/examples/CQL/CompanyDirectorEmployee.cql +2 -2
- data/examples/CQL/Death.cql +1 -1
- data/examples/CQL/Diplomacy.cql +9 -9
- data/examples/CQL/Genealogy.cql +3 -2
- data/examples/CQL/Insurance.cql +10 -7
- data/examples/CQL/JoinEquality.cql +2 -2
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +73 -53
- data/examples/CQL/MetamodelNext.cql +89 -67
- data/examples/CQL/OneToOnes.cql +2 -2
- data/examples/CQL/ServiceDirector.cql +10 -5
- data/examples/CQL/Supervision.cql +3 -3
- data/examples/CQL/Tests.Test5.Load.cql +1 -1
- data/examples/CQL/Warehousing.cql +4 -2
- data/lib/activefacts/cql/CQLParser.treetop +26 -60
- data/lib/activefacts/cql/Context.treetop +12 -2
- data/lib/activefacts/cql/Expressions.treetop +14 -30
- data/lib/activefacts/cql/FactTypes.treetop +165 -110
- data/lib/activefacts/cql/Language/English.treetop +167 -54
- data/lib/activefacts/cql/LexicalRules.treetop +16 -2
- data/lib/activefacts/cql/{Concepts.treetop → ObjectTypes.treetop} +36 -37
- data/lib/activefacts/cql/Terms.treetop +57 -27
- data/lib/activefacts/cql/ValueTypes.treetop +39 -13
- data/lib/activefacts/cql/compiler.rb +5 -3
- data/lib/activefacts/cql/compiler/{reading.rb → clause.rb} +407 -285
- data/lib/activefacts/cql/compiler/constraint.rb +178 -275
- data/lib/activefacts/cql/compiler/entity_type.rb +73 -64
- data/lib/activefacts/cql/compiler/expression.rb +418 -0
- data/lib/activefacts/cql/compiler/fact.rb +146 -145
- data/lib/activefacts/cql/compiler/fact_type.rb +197 -80
- data/lib/activefacts/cql/compiler/join.rb +159 -0
- data/lib/activefacts/cql/compiler/shared.rb +51 -23
- data/lib/activefacts/cql/compiler/value_type.rb +56 -2
- data/lib/activefacts/cql/parser.rb +15 -4
- data/lib/activefacts/generate/absorption.rb +7 -7
- data/lib/activefacts/generate/cql.rb +100 -37
- data/lib/activefacts/generate/oo.rb +28 -51
- data/lib/activefacts/generate/ordered.rb +60 -36
- data/lib/activefacts/generate/ruby.rb +6 -6
- data/lib/activefacts/generate/sql/server.rb +4 -4
- data/lib/activefacts/input/orm.rb +71 -53
- data/lib/activefacts/persistence.rb +1 -1
- data/lib/activefacts/persistence/columns.rb +27 -23
- data/lib/activefacts/persistence/foreignkey.rb +6 -6
- data/lib/activefacts/persistence/index.rb +17 -17
- data/lib/activefacts/persistence/{concept.rb → object_type.rb} +9 -9
- data/lib/activefacts/persistence/reference.rb +61 -36
- data/lib/activefacts/persistence/tables.rb +61 -59
- data/lib/activefacts/support.rb +54 -29
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary/extensions.rb +99 -54
- data/lib/activefacts/vocabulary/metamodel.rb +43 -37
- data/lib/activefacts/vocabulary/verbaliser.rb +134 -109
- data/spec/absorption_spec.rb +8 -8
- data/spec/cql/comparison_spec.rb +91 -0
- data/spec/cql/contractions_spec.rb +251 -0
- data/spec/cql/entity_type_spec.rb +319 -0
- data/spec/cql/expressions_spec.rb +63 -0
- data/spec/cql/fact_type_matching_spec.rb +283 -0
- data/spec/cql/french_spec.rb +21 -0
- data/spec/cql/parser/bad_literals_spec.rb +86 -0
- data/spec/cql/parser/constraints_spec.rb +19 -0
- data/spec/cql/parser/entity_types_spec.rb +106 -0
- data/spec/cql/parser/expressions_spec.rb +179 -0
- data/spec/cql/parser/fact_types_spec.rb +41 -0
- data/spec/cql/parser/literals_spec.rb +312 -0
- data/spec/cql/parser/pragmas_spec.rb +89 -0
- data/spec/cql/parser/value_types_spec.rb +42 -0
- data/spec/cql/role_matching_spec.rb +147 -0
- data/spec/cql/samples_spec.rb +9 -9
- data/spec/cql_cql_spec.rb +1 -1
- data/spec/cql_dm_spec.rb +116 -0
- data/spec/cql_mysql_spec.rb +1 -1
- data/spec/cql_ruby_spec.rb +1 -1
- data/spec/cql_sql_spec.rb +3 -3
- data/spec/cql_symbol_tables_spec.rb +30 -30
- data/spec/cqldump_spec.rb +4 -4
- data/spec/helpers/array_matcher.rb +32 -27
- data/spec/helpers/diff_matcher.rb +6 -26
- data/spec/helpers/file_matcher.rb +41 -32
- data/spec/helpers/parse_to_ast_matcher.rb +76 -0
- data/spec/helpers/string_matcher.rb +32 -31
- data/spec/norma_cql_spec.rb +1 -1
- data/spec/norma_ruby_spec.rb +1 -1
- data/spec/norma_ruby_sql_spec.rb +1 -1
- data/spec/norma_sql_spec.rb +3 -1
- data/spec/norma_tables_spec.rb +1 -1
- data/spec/ruby_api_spec.rb +23 -0
- data/spec/spec_helper.rb +5 -4
- metadata +66 -66
- data/examples/CQL/OrienteeringER.cql +0 -58
- data/lib/activefacts/api.rb +0 -44
- data/lib/activefacts/api/concept.rb +0 -410
- data/lib/activefacts/api/constellation.rb +0 -128
- data/lib/activefacts/api/entity.rb +0 -256
- data/lib/activefacts/api/instance.rb +0 -60
- data/lib/activefacts/api/instance_index.rb +0 -80
- data/lib/activefacts/api/numeric.rb +0 -167
- data/lib/activefacts/api/role.rb +0 -80
- data/lib/activefacts/api/role_proxy.rb +0 -70
- data/lib/activefacts/api/role_values.rb +0 -117
- data/lib/activefacts/api/standard_types.rb +0 -87
- data/lib/activefacts/api/support.rb +0 -65
- data/lib/activefacts/api/value.rb +0 -135
- data/lib/activefacts/api/vocabulary.rb +0 -82
- data/spec/api/autocounter.rb +0 -82
- data/spec/api/constellation.rb +0 -130
- data/spec/api/entity_type.rb +0 -103
- data/spec/api/instance.rb +0 -461
- data/spec/api/roles.rb +0 -124
- data/spec/api/value_type.rb +0 -112
- data/spec/api_spec.rb +0 -13
- data/spec/cql/matching_spec.rb +0 -517
- data/spec/cql/unit_spec.rb +0 -394
- data/spec/spec.opts +0 -1
|
@@ -29,8 +29,8 @@ module ActiveFacts
|
|
|
29
29
|
:discussion => @discussion
|
|
30
30
|
)
|
|
31
31
|
case target
|
|
32
|
-
when ActiveFacts::Metamodel::
|
|
33
|
-
context_note.
|
|
32
|
+
when ActiveFacts::Metamodel::ObjectType
|
|
33
|
+
context_note.object_type = target
|
|
34
34
|
when ActiveFacts::Metamodel::Constraint
|
|
35
35
|
context_note.constraint = target
|
|
36
36
|
when ActiveFacts::Metamodel::FactType
|
|
@@ -52,10 +52,13 @@ module ActiveFacts
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
class Constraint < Definition
|
|
55
|
-
def initialize context_note, enforcement,
|
|
55
|
+
def initialize context_note, enforcement, clauses_lists = []
|
|
56
|
+
if context_note.is_a?(Treetop::Runtime::SyntaxNode)
|
|
57
|
+
context_note = context_note.empty? ? nil : context_note.ast
|
|
58
|
+
end
|
|
56
59
|
@context_note = context_note
|
|
57
60
|
@enforcement = enforcement
|
|
58
|
-
@
|
|
61
|
+
@clauses_lists = clauses_lists
|
|
59
62
|
end
|
|
60
63
|
|
|
61
64
|
def compile
|
|
@@ -67,38 +70,29 @@ module ActiveFacts
|
|
|
67
70
|
# Override for constraint types that need loose binding (same role player matching with different adjectives)
|
|
68
71
|
end
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
def all_bindings_in_readings readings
|
|
72
|
-
readings.map do |reading|
|
|
73
|
-
reading.role_refs.map do |rr|
|
|
74
|
-
[rr.binding] + (rr.objectification_join ? all_bindings_in_readings(rr.objectification_join) : [])
|
|
75
|
-
end
|
|
76
|
-
end.
|
|
77
|
-
flatten.
|
|
78
|
-
uniq
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def bind_readings
|
|
73
|
+
def bind_clauses extra = []
|
|
82
74
|
@context = CompilationContext.new(@vocabulary)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
fact_type =
|
|
90
|
-
raise "Unrecognised fact type #{
|
|
75
|
+
@context.left_contraction_allowed = true
|
|
76
|
+
|
|
77
|
+
@context.bind @clauses_lists, extra
|
|
78
|
+
@clauses_lists.map do |clauses_list|
|
|
79
|
+
@context.left_contractable_clause = nil # Don't contract outside this set of clauses
|
|
80
|
+
clauses_list.each do |clause|
|
|
81
|
+
fact_type = clause.match_existing_fact_type @context
|
|
82
|
+
raise "Unrecognised fact type #{clause.inspect} in #{self.class}" unless fact_type
|
|
91
83
|
end
|
|
92
84
|
end
|
|
93
85
|
|
|
86
|
+
# Any constrained roles will be first identified here.
|
|
87
|
+
# This means that they can't introduce role names.
|
|
94
88
|
loose_binding
|
|
95
89
|
|
|
96
90
|
# Ok, we have bound all players by subscript/role_name, by adjectives, and by loose binding,
|
|
97
91
|
# and matched all the fact types that matter. Now assemble a join (with all join steps) for
|
|
98
|
-
# each join list, and build an array of the
|
|
99
|
-
@
|
|
100
|
-
@
|
|
101
|
-
|
|
92
|
+
# each join list, and build an array of the variables that are involved in the join steps.
|
|
93
|
+
@variables_by_list =
|
|
94
|
+
@clauses_lists.map do |clauses_list|
|
|
95
|
+
all_variables_in_clauses(clauses_list)
|
|
102
96
|
end
|
|
103
97
|
|
|
104
98
|
warn_ignored_joins
|
|
@@ -106,8 +100,8 @@ module ActiveFacts
|
|
|
106
100
|
|
|
107
101
|
def warn_ignored_joins
|
|
108
102
|
# Warn about ignored joins
|
|
109
|
-
@
|
|
110
|
-
fact_types =
|
|
103
|
+
@clauses_lists.each do |clauses_list|
|
|
104
|
+
fact_types = clauses_list.map{|join| join.var_refs[0].role_ref.role.fact_type}.uniq
|
|
111
105
|
if fact_types.size > 1
|
|
112
106
|
puts "------->>>> Join ignored in #{self.class}: #{fact_types.map{|ft| ft.preferred_reading.expand}*' and '}"
|
|
113
107
|
end
|
|
@@ -117,63 +111,61 @@ module ActiveFacts
|
|
|
117
111
|
def loose_bind_wherever_possible
|
|
118
112
|
# Apply loose binding over applicable roles:
|
|
119
113
|
debug :binding, "Loose binding on #{self.class.name}" do
|
|
120
|
-
@
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
next if
|
|
124
|
-
# if
|
|
125
|
-
# debug :binding, "Discounting #{
|
|
114
|
+
@clauses_lists.each do |clauses_list|
|
|
115
|
+
clauses_list.each do |clause|
|
|
116
|
+
clause.var_refs.each_with_index do |var_ref, i|
|
|
117
|
+
next if var_ref.variable.refs.size > 1
|
|
118
|
+
# if clause.side_effects && !clause.side_effects.role_side_effects[i].residual_adjectives
|
|
119
|
+
# debug :binding, "Discounting #{var_ref.inspect} as needing loose binding because it has no residual_adjectives"
|
|
126
120
|
# next
|
|
127
121
|
# end
|
|
128
|
-
# This
|
|
129
|
-
candidates = @context.
|
|
130
|
-
select do |key,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# REVISIT: Don't bind to a
|
|
135
|
-
!
|
|
136
|
-
x =
|
|
137
|
-
# puts "Discounting
|
|
122
|
+
# This var_ref didn't match any other var_ref. Have a scout around for a suitable partner
|
|
123
|
+
candidates = @context.variables.
|
|
124
|
+
select do |key, variable|
|
|
125
|
+
variable.player == var_ref.variable.player and
|
|
126
|
+
variable != var_ref.variable and
|
|
127
|
+
variable.role_name == var_ref.variable.role_name and # Both will be nil if they match
|
|
128
|
+
# REVISIT: Don't bind to a variable with a role occurrence in the same clause
|
|
129
|
+
!variable.refs.detect{|vr|
|
|
130
|
+
x = vr.clause == clause
|
|
131
|
+
# puts "Discounting variable #{variable.inspect} as a match for #{var_ref.inspect} because it's already bound to a player in #{var_ref.clause.inspect}" if x
|
|
138
132
|
x
|
|
139
133
|
}
|
|
140
134
|
end.map{|k,b| b}
|
|
141
135
|
next if candidates.size != 1 # Fail
|
|
142
|
-
debug :binding, "Loose binding #{
|
|
143
|
-
|
|
136
|
+
debug :binding, "Loose binding #{var_ref.inspect} to #{candidates[0].inspect}"
|
|
137
|
+
var_ref.rebind_to(@context, candidates[0].refs[0])
|
|
144
138
|
end
|
|
145
139
|
end
|
|
146
140
|
end
|
|
147
141
|
end
|
|
148
142
|
end
|
|
149
143
|
|
|
150
|
-
def
|
|
144
|
+
def loose_bind
|
|
151
145
|
# Apply loose binding over applicable @roles:
|
|
152
146
|
debug :binding, "Check for loose bindings on #{@roles.size} roles in #{self.class.name}" do
|
|
153
|
-
@roles.each do |
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
debug :binding, "Insufficient bindings for #{role_ref.inspect} (#{role_ref.binding.refs.size}, expected #{@readings_lists.size+1}), attempting loose binding" do
|
|
158
|
-
@readings_lists.each do |readings_list|
|
|
147
|
+
@roles.each do |var_ref|
|
|
148
|
+
if var_ref.variable.refs.size < @clauses_lists.size+1
|
|
149
|
+
debug :binding, "Insufficient bindings for #{var_ref.inspect} (#{var_ref.variable.refs.size}, expected #{@clauses_lists.size+1}), attempting loose binding" do
|
|
150
|
+
@clauses_lists.each do |clauses_list|
|
|
159
151
|
candidates = []
|
|
160
|
-
next if
|
|
161
|
-
detect do |
|
|
162
|
-
debug :binding, "Checking #{
|
|
163
|
-
|
|
164
|
-
detect do |
|
|
165
|
-
already_bound =
|
|
166
|
-
if !already_bound &&
|
|
167
|
-
candidates <<
|
|
152
|
+
next if clauses_list.
|
|
153
|
+
detect do |clause|
|
|
154
|
+
debug :binding, "Checking #{clause.inspect}"
|
|
155
|
+
clause.var_refs.
|
|
156
|
+
detect do |vr|
|
|
157
|
+
already_bound = vr.variable == var_ref.variable
|
|
158
|
+
if !already_bound && vr.player == var_ref.player
|
|
159
|
+
candidates << vr
|
|
168
160
|
end
|
|
169
161
|
already_bound
|
|
170
162
|
end
|
|
171
163
|
end
|
|
172
|
-
debug :binding, "Attempting loose binding for #{
|
|
164
|
+
debug :binding, "Attempting loose binding for #{var_ref.inspect} in #{clauses_list.inspect}, from the following candidates: #{candidates.inspect}"
|
|
173
165
|
|
|
174
166
|
if candidates.size == 1
|
|
175
|
-
debug :binding, "Rebinding #{candidates[0].inspect} to #{
|
|
176
|
-
candidates[0].rebind_to(@context,
|
|
167
|
+
debug :binding, "Rebinding #{candidates[0].inspect} to #{var_ref.inspect}"
|
|
168
|
+
candidates[0].rebind_to(@context, var_ref)
|
|
177
169
|
end
|
|
178
170
|
end
|
|
179
171
|
end
|
|
@@ -182,41 +174,45 @@ module ActiveFacts
|
|
|
182
174
|
end
|
|
183
175
|
end
|
|
184
176
|
|
|
185
|
-
def
|
|
186
|
-
@
|
|
187
|
-
raise "#{self.class} must cover some of the same roles, see #{@
|
|
188
|
-
@
|
|
177
|
+
def common_variables
|
|
178
|
+
@common_variables ||= @variables_by_list[1..-1].inject(@variables_by_list[0]) { |r, b| r & b }
|
|
179
|
+
raise "#{self.class} must cover some of the same roles, see #{@variables_by_list.inspect}" unless @common_variables.size > 0
|
|
180
|
+
@common_variables
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def to_s
|
|
184
|
+
"#{self.class.name.sub(/.*::/,'')}" + (@clauses_lists.size > 0 ? " over #{@clauses_lists.inspect}" : '')
|
|
189
185
|
end
|
|
190
186
|
end
|
|
191
187
|
|
|
192
188
|
class PresenceConstraint < Constraint
|
|
193
|
-
def initialize context_note, enforcement,
|
|
194
|
-
super context_note, enforcement,
|
|
195
|
-
@
|
|
189
|
+
def initialize context_note, enforcement, clauses_lists, var_refs, quantifier
|
|
190
|
+
super context_note, enforcement, clauses_lists
|
|
191
|
+
@var_refs = var_refs || []
|
|
196
192
|
@quantifier = quantifier
|
|
197
193
|
end
|
|
198
194
|
|
|
199
195
|
def compile
|
|
200
|
-
@
|
|
201
|
-
raise "REVISIT: Join presence constraints not supported yet" if
|
|
202
|
-
|
|
203
|
-
|
|
196
|
+
@clauses = @clauses_lists.map do |clauses_list|
|
|
197
|
+
raise "REVISIT: Join presence constraints not supported yet" if clauses_list.size > 1 or
|
|
198
|
+
clauses_list.detect{|clause| clause.var_refs.detect{|vr| vr.nested_clauses } }
|
|
199
|
+
clauses_list[0]
|
|
204
200
|
end
|
|
205
201
|
|
|
206
|
-
|
|
202
|
+
bind_clauses @var_refs
|
|
207
203
|
|
|
208
|
-
if @
|
|
209
|
-
|
|
204
|
+
if @var_refs.size > 0
|
|
205
|
+
bind_constrained_roles
|
|
210
206
|
else
|
|
211
|
-
cb =
|
|
207
|
+
cb = common_variables
|
|
212
208
|
raise "Either/or must have only one duplicated role, not #{cb.inspect}" unless cb.size == 1
|
|
213
|
-
@
|
|
209
|
+
@var_refs = cb[0].refs.reverse # REVISIT: Should have order these by clause, not like this
|
|
214
210
|
end
|
|
215
211
|
|
|
216
212
|
role_sequence = @constellation.RoleSequence(:new)
|
|
217
|
-
@
|
|
218
|
-
raise "The constrained role #{
|
|
219
|
-
(
|
|
213
|
+
@var_refs.each do |var_ref|
|
|
214
|
+
raise "The constrained role #{var_ref.inspect} was not found in the invoked fact types" if var_ref.variable.refs.size == 1
|
|
215
|
+
(var_ref.variable.refs-[var_ref]).each do |ref|
|
|
220
216
|
role = (ref.role_ref && ref.role_ref.role) || ref.role
|
|
221
217
|
raise "FactType role not found for #{ref.inspect}" unless role
|
|
222
218
|
@constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => role)
|
|
@@ -238,207 +234,87 @@ module ActiveFacts
|
|
|
238
234
|
super
|
|
239
235
|
end
|
|
240
236
|
|
|
241
|
-
# In a PresenceConstraint, each role in "each XYZ" must occur in exactly one
|
|
237
|
+
# In a PresenceConstraint, each role in "each XYZ" must occur in exactly one clauses_list
|
|
242
238
|
def loose_binding
|
|
243
239
|
# loose_bind_wherever_possible
|
|
244
240
|
end
|
|
245
241
|
|
|
246
|
-
def
|
|
247
|
-
@
|
|
248
|
-
|
|
249
|
-
role_ref.bind @context
|
|
250
|
-
if role_ref.binding.refs.size == 1
|
|
242
|
+
def bind_constrained_roles
|
|
243
|
+
@var_refs.each do |var_ref|
|
|
244
|
+
if var_ref.variable.refs.size == 1
|
|
251
245
|
# Apply loose binding over the constrained roles
|
|
252
246
|
candidates =
|
|
253
|
-
@
|
|
254
|
-
|
|
247
|
+
@clauses.map do |clause|
|
|
248
|
+
clause.var_refs.select{ |vr| vr.player == var_ref.player }
|
|
255
249
|
end.flatten
|
|
256
250
|
if candidates.size == 1
|
|
257
|
-
debug :binding, "Rebinding #{
|
|
258
|
-
|
|
251
|
+
debug :binding, "Rebinding #{var_ref.inspect} to #{candidates[0].inspect} in presence constraint"
|
|
252
|
+
var_ref.rebind_to(@context, candidates[0])
|
|
259
253
|
end
|
|
260
254
|
end
|
|
261
255
|
end
|
|
262
256
|
end
|
|
263
257
|
|
|
258
|
+
def to_s
|
|
259
|
+
"#{super} #{@quantifier.min}-#{@quantifier.max} over (#{@var_refs.map{|vr| vr.inspect}*', '})"
|
|
260
|
+
end
|
|
264
261
|
end
|
|
265
262
|
|
|
266
263
|
class SetConstraint < Constraint
|
|
267
|
-
def initialize context_note, enforcement,
|
|
268
|
-
super context_note, enforcement,
|
|
264
|
+
def initialize context_note, enforcement, clauses_lists
|
|
265
|
+
super context_note, enforcement, clauses_lists
|
|
269
266
|
end
|
|
270
267
|
|
|
271
268
|
def warn_ignored_joins
|
|
272
269
|
# No warnings needed here any more
|
|
273
270
|
end
|
|
274
271
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
binding.join_node = @constellation.JoinNode(join, join.all_join_node.size, :concept => binding.player)
|
|
283
|
-
end
|
|
284
|
-
join
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def build_join_steps reading, constrained_rs, objectification_node = nil
|
|
289
|
-
join_roles = []
|
|
290
|
-
incidental_roles = []
|
|
291
|
-
debug :join, "Creating join Role Sequence for #{reading.inspect} with #{reading.role_refs.size} role refs" do
|
|
292
|
-
objectification_step = nil
|
|
293
|
-
reading.role_refs.each do |role_ref|
|
|
294
|
-
# These role_refs are the Compiler::RoleRefs. These have associated Metamodel::RoleRefs,
|
|
295
|
-
# but we need to create JoinRoles for those roles. # REVISIT: JoinRoles may need to save residual_adjectives
|
|
296
|
-
binding = role_ref.binding
|
|
297
|
-
role = role_ref.role || role_ref.role_ref.role
|
|
298
|
-
join_role = nil
|
|
299
|
-
|
|
300
|
-
if (reading.fact_type.entity_type)
|
|
301
|
-
# This reading is of an objectified fact type.
|
|
302
|
-
# We need a join step from this role to the phantom role, but not
|
|
303
|
-
# for a role that has only one role_ref (this one) in their binding.
|
|
304
|
-
# Create the JoinNode and JoinRole in any case though.
|
|
305
|
-
refs_count = binding.refs.size
|
|
306
|
-
objectification_ref_count = 0
|
|
307
|
-
if role_ref.objectification_join
|
|
308
|
-
role_ref.objectification_join.each do |r|
|
|
309
|
-
objectification_ref_count += r.role_refs.select{|rr| rr.binding.refs.size > 1}.size
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
refs_count += objectification_ref_count
|
|
313
|
-
|
|
314
|
-
debug :join, "Creating Join Node #{role_ref.inspect} (counts #{refs_count}/#{objectification_ref_count}) and objectification Join Step for #{role_ref.inspect}" do
|
|
272
|
+
def role_sequences_for_common_variables ignore_trailing_joins = false
|
|
273
|
+
@clauses_lists.
|
|
274
|
+
zip(@variables_by_list).
|
|
275
|
+
map do |clauses_list, variables|
|
|
276
|
+
# Does this clauses_list involve a join?
|
|
277
|
+
if clauses_list.size > 1 or
|
|
278
|
+
clauses_list.detect{|clause| clause.var_refs.detect{|var_ref| var_ref.nested_clauses } }
|
|
315
279
|
|
|
316
|
-
|
|
317
|
-
|
|
280
|
+
debug :join, "Building join for #{clauses_list.inspect}" do
|
|
281
|
+
debug :join, "Constrained variables are #{@common_variables.inspect}"
|
|
282
|
+
# Every Variable in these clauses becomes a Join Node,
|
|
283
|
+
# and every clause becomes a JoinStep (and a RoleSequence).
|
|
284
|
+
# The returned RoleSequences contains the RoleRefs for the common_variables.
|
|
318
285
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
incidental_roles << join_role
|
|
324
|
-
end
|
|
325
|
-
next
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
join_roles << join_role
|
|
329
|
-
unless objectification_node
|
|
330
|
-
# This is an implicit objectification, just the FT reading, not ET(where ...reading...)
|
|
331
|
-
# We need to create a JoinNode for this object, even though it has no RoleRefs
|
|
332
|
-
join = binding.join_node.join
|
|
333
|
-
debug :join, "Creating JN#{join.all_join_node.size} for #{reading.fact_type.entity_type.name} in objectification"
|
|
334
|
-
objectification_node = @constellation.JoinNode(join, join.all_join_node.size, :concept => reading.fact_type.entity_type)
|
|
335
|
-
end
|
|
336
|
-
raise "Internal error: Trying to add role of #{role.implicit_fact_type.all_role.single.concept.name} to join node for #{objectification_node.concept.name}" unless objectification_node.concept == role.implicit_fact_type.all_role.single.concept
|
|
337
|
-
|
|
338
|
-
irole = role.implicit_fact_type.all_role.single
|
|
339
|
-
raise "Internal error: Trying to add role of #{irole.concept.name} to join node for #{objectification_node.concept.name}" unless objectification_node.concept == irole.concept
|
|
340
|
-
objectification_role = @constellation.JoinRole(objectification_node, role.implicit_fact_type.all_role.single)
|
|
341
|
-
objectification_step = @constellation.JoinStep(objectification_role, join_role, :fact_type => role.implicit_fact_type)
|
|
342
|
-
debug :join, "New #{objectification_step.describe}"
|
|
343
|
-
debug :join, "Associating #{incidental_roles.map(&:describe)*', '} incidental roles with #{objectification_step.describe}" if incidental_roles.size > 0
|
|
344
|
-
incidental_roles.each { |jr| jr.join_step = objectification_step }
|
|
345
|
-
incidental_roles = []
|
|
346
|
-
join_roles = []
|
|
347
|
-
end
|
|
348
|
-
else
|
|
349
|
-
debug :join, "Creating Role Ref for #{role_ref.inspect}" do
|
|
350
|
-
# REVISIT: If there's an implicit subtyping join here, create it; then always raise the error here.
|
|
351
|
-
# I don't want to do this for now because the verbaliser will always verbalise all join steps.
|
|
352
|
-
if binding.join_node.concept != role.concept and
|
|
353
|
-
0 == (binding.join_node.concept.supertypes_transitive & role.concept.supertypes_transitive).size
|
|
354
|
-
raise "Internal error: Trying to add role of #{role.concept.name} to join node for #{binding.join_node.concept.name} in '#{reading.fact_type.default_reading}'"
|
|
355
|
-
end
|
|
356
|
-
raise "Internal error: Trying to add role of #{role.concept.name} to join node for #{binding.join_node.concept.name}" unless binding.join_node.concept == role.concept
|
|
357
|
-
join_role = @constellation.JoinRole(binding.join_node, role)
|
|
358
|
-
join_roles << join_role
|
|
359
|
-
end
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
if role_ref.objectification_join
|
|
363
|
-
# We are looking at a role whose player is an objectification of a fact type,
|
|
364
|
-
# which will have ImplicitFactTypes for each role.
|
|
365
|
-
# Each of these ImplicitFactTypes has a single phantom role played by the objectifying entity type
|
|
366
|
-
# One of these phantom roles is likely to be the subject of an objectification join step.
|
|
367
|
-
role_ref.objectification_join.each do |r|
|
|
368
|
-
debug :join, "Building objectification join for #{role_ref.objectification_join.inspect}" do
|
|
369
|
-
build_join_steps r, constrained_rs, binding.join_node
|
|
370
|
-
end
|
|
371
|
-
end
|
|
372
|
-
end
|
|
373
|
-
if (@common_bindings.include?(binding))
|
|
374
|
-
debug :join, "#{binding.inspect} is a constrained binding, add the Role Ref for #{role.concept.name}"
|
|
375
|
-
raise "Internal error: Trying to add role of #{role.concept.name} to join node for #{binding.join_node.concept.name}" unless binding.join_node.concept == role.concept
|
|
376
|
-
@constellation.RoleRef(constrained_rs, constrained_rs.all_role_ref.size, :role => role, :join_role => join_role)
|
|
377
|
-
end
|
|
378
|
-
end
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
if join_roles.size > 0
|
|
382
|
-
end_node = join_roles[-1].join_node
|
|
383
|
-
if !reading.fact_type.entity_type and role = reading.fact_type.all_role.single
|
|
384
|
-
# Don't give the ImplicitBoolean a join_node. We can live without one, for now.
|
|
385
|
-
# The Join Step will have a duplicate node, and the fact type will tell us what's happening
|
|
386
|
-
join_roles << join_roles[0]
|
|
387
|
-
end
|
|
388
|
-
# We aren't talking about objectification here, so there must be exactly two roles.
|
|
389
|
-
raise "REVISIT: Internal error constructing join for #{reading.inspect}" if join_roles.size != 2
|
|
390
|
-
js = @constellation.JoinStep(join_roles[0], join_roles[1], :fact_type => reading.fact_type)
|
|
391
|
-
debug :join, "New Join Step #{js.describe}"
|
|
392
|
-
debug :join, "Associating #{incidental_roles.map(&:describe)*', '} incidental roles with #{js.describe}" if incidental_roles.size > 0
|
|
393
|
-
incidental_roles.each { |jr| jr.join_step = js }
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
def role_sequences_for_common_bindings ignore_trailing_joins = false
|
|
398
|
-
@readings_lists.
|
|
399
|
-
zip(@bindings_by_list).
|
|
400
|
-
map do |readings_list, bindings|
|
|
401
|
-
# Does this readings_list involve a join?
|
|
402
|
-
if readings_list.size > 1 or
|
|
403
|
-
readings_list.detect{|reading| reading.role_refs.detect{|role_ref| role_ref.objectification_join } }
|
|
404
|
-
|
|
405
|
-
debug :join, "Building join for #{readings_list.inspect}" do
|
|
406
|
-
debug :join, "Constrained bindings are #{@common_bindings.inspect}"
|
|
407
|
-
# Every Binding in these readings becomes a Join Node,
|
|
408
|
-
# and every reading becomes a JoinStep (and a RoleSequence).
|
|
409
|
-
# The returned RoleSequences contains the RoleRefs for the common_bindings.
|
|
410
|
-
|
|
411
|
-
# Create a join with a join node for every binding:
|
|
412
|
-
join = build_join_nodes(readings_list)
|
|
286
|
+
# Create a join with a join node for every variable and all join steps:
|
|
287
|
+
join = build_join_nodes(clauses_list)
|
|
288
|
+
roles_by_variable = build_all_join_steps(clauses_list)
|
|
289
|
+
join.validate
|
|
413
290
|
|
|
291
|
+
# Create the projected RoleSequence for the constraint:
|
|
414
292
|
role_sequence = @constellation.RoleSequence(:new)
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
end
|
|
293
|
+
@common_variables.each do |variable|
|
|
294
|
+
role, join_role = *roles_by_variable[variable]
|
|
295
|
+
@constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => role, :join_role => join_role)
|
|
419
296
|
end
|
|
420
|
-
join.validate
|
|
421
297
|
|
|
422
298
|
role_sequence
|
|
423
299
|
end
|
|
424
300
|
else
|
|
425
|
-
# There's no join in this
|
|
301
|
+
# There's no join in this clauses_list, just create a role_sequence
|
|
426
302
|
role_sequence = @constellation.RoleSequence(:new)
|
|
427
|
-
|
|
428
|
-
unless
|
|
429
|
-
debug :constraint, "REVISIT: #{self.class}: Ignoring join from #{@
|
|
303
|
+
join_variables = variables-@common_variables
|
|
304
|
+
unless join_variables.empty? or ignore_trailing_joins && join_variables.size <= 1
|
|
305
|
+
debug :constraint, "REVISIT: #{self.class}: Ignoring join from #{@common_variables.inspect} to #{join_variables.inspect} in #{clauses_list.inspect}"
|
|
430
306
|
end
|
|
431
|
-
@
|
|
432
|
-
roles =
|
|
433
|
-
map do |
|
|
434
|
-
|
|
307
|
+
@common_variables.each do |variable|
|
|
308
|
+
roles = clauses_list.
|
|
309
|
+
map do |clause|
|
|
310
|
+
clause.var_refs.detect{|vr| vr.variable == variable }
|
|
435
311
|
end.
|
|
436
|
-
compact. # A join
|
|
437
|
-
map do |
|
|
438
|
-
|
|
312
|
+
compact. # A join clause will probably not have the common variable
|
|
313
|
+
map do |var_ref|
|
|
314
|
+
var_ref.role_ref && var_ref.role_ref.role or var_ref.role
|
|
439
315
|
end.
|
|
440
316
|
compact
|
|
441
|
-
# REVISIT: Should use
|
|
317
|
+
# REVISIT: Should use clause side effects to preserve residual adjectives here.
|
|
442
318
|
@constellation.RoleRef(role_sequence, role_sequence.all_role_ref.size, :role => roles[0])
|
|
443
319
|
end
|
|
444
320
|
role_sequence
|
|
@@ -448,18 +324,18 @@ module ActiveFacts
|
|
|
448
324
|
end
|
|
449
325
|
|
|
450
326
|
class SubsetConstraint < SetConstraint
|
|
451
|
-
def initialize context_note, enforcement,
|
|
452
|
-
super context_note, enforcement,
|
|
453
|
-
@
|
|
454
|
-
@
|
|
327
|
+
def initialize context_note, enforcement, clauses_lists
|
|
328
|
+
super context_note, enforcement, clauses_lists
|
|
329
|
+
@subset_clauses = @clauses_lists[0]
|
|
330
|
+
@superset_clauses = @clauses_lists[1]
|
|
455
331
|
end
|
|
456
332
|
|
|
457
333
|
def compile
|
|
458
|
-
|
|
459
|
-
|
|
334
|
+
bind_clauses
|
|
335
|
+
common_variables
|
|
460
336
|
|
|
461
337
|
role_sequences =
|
|
462
|
-
|
|
338
|
+
role_sequences_for_common_variables
|
|
463
339
|
|
|
464
340
|
@constraint =
|
|
465
341
|
@constellation.SubsetConstraint(
|
|
@@ -478,24 +354,24 @@ module ActiveFacts
|
|
|
478
354
|
end
|
|
479
355
|
|
|
480
356
|
class SetComparisonConstraint < SetConstraint
|
|
481
|
-
def initialize context_note, enforcement,
|
|
482
|
-
super context_note, enforcement,
|
|
357
|
+
def initialize context_note, enforcement, clauses_lists
|
|
358
|
+
super context_note, enforcement, clauses_lists
|
|
483
359
|
end
|
|
484
360
|
end
|
|
485
361
|
|
|
486
362
|
class SetExclusionConstraint < SetComparisonConstraint
|
|
487
|
-
def initialize context_note, enforcement,
|
|
488
|
-
super context_note, enforcement,
|
|
363
|
+
def initialize context_note, enforcement, clauses_lists, roles, quantifier
|
|
364
|
+
super context_note, enforcement, clauses_lists
|
|
489
365
|
@roles = roles || []
|
|
490
366
|
@quantifier = quantifier
|
|
491
367
|
end
|
|
492
368
|
|
|
493
369
|
def compile
|
|
494
|
-
|
|
495
|
-
|
|
370
|
+
bind_clauses @roles
|
|
371
|
+
common_variables
|
|
496
372
|
|
|
497
373
|
role_sequences =
|
|
498
|
-
|
|
374
|
+
role_sequences_for_common_variables
|
|
499
375
|
|
|
500
376
|
@constraint = @constellation.SetExclusionConstraint(
|
|
501
377
|
:new,
|
|
@@ -509,28 +385,28 @@ module ActiveFacts
|
|
|
509
385
|
super
|
|
510
386
|
end
|
|
511
387
|
|
|
512
|
-
# In a SetExclusionConstraint, each role in "for each XYZ" must occur in each
|
|
388
|
+
# In a SetExclusionConstraint, each role in "for each XYZ" must occur in each clauses_list
|
|
513
389
|
def loose_binding
|
|
514
390
|
if @roles.size == 0
|
|
515
391
|
loose_bind_wherever_possible
|
|
516
392
|
else
|
|
517
|
-
|
|
393
|
+
loose_bind
|
|
518
394
|
end
|
|
519
395
|
end
|
|
520
396
|
|
|
521
397
|
end
|
|
522
398
|
|
|
523
399
|
class SetEqualityConstraint < SetComparisonConstraint
|
|
524
|
-
def initialize context_note, enforcement,
|
|
525
|
-
super context_note, enforcement,
|
|
400
|
+
def initialize context_note, enforcement, clauses_lists
|
|
401
|
+
super context_note, enforcement, clauses_lists
|
|
526
402
|
end
|
|
527
403
|
|
|
528
404
|
def compile
|
|
529
|
-
|
|
530
|
-
|
|
405
|
+
bind_clauses
|
|
406
|
+
common_variables
|
|
531
407
|
|
|
532
408
|
role_sequences =
|
|
533
|
-
|
|
409
|
+
role_sequences_for_common_variables
|
|
534
410
|
|
|
535
411
|
@constraint = @constellation.SetEqualityConstraint(
|
|
536
412
|
:new,
|
|
@@ -546,7 +422,6 @@ module ActiveFacts
|
|
|
546
422
|
def loose_binding
|
|
547
423
|
loose_bind_wherever_possible
|
|
548
424
|
end
|
|
549
|
-
|
|
550
425
|
end
|
|
551
426
|
|
|
552
427
|
class RingConstraint < Constraint
|
|
@@ -564,10 +439,10 @@ module ActiveFacts
|
|
|
564
439
|
# Process the ring constraints:
|
|
565
440
|
return if @rings.empty?
|
|
566
441
|
|
|
567
|
-
role_refs = @role_sequence.
|
|
442
|
+
role_refs = @role_sequence.all_role_ref_in_order.to_a
|
|
568
443
|
supertypes_by_position = role_refs.
|
|
569
444
|
map do |role_ref|
|
|
570
|
-
role_ref.role.
|
|
445
|
+
role_ref.role.object_type.supertypes_transitive
|
|
571
446
|
end
|
|
572
447
|
role_pairs = []
|
|
573
448
|
supertypes_by_position.each_with_index do |sts, i|
|
|
@@ -606,16 +481,22 @@ module ActiveFacts
|
|
|
606
481
|
debug :constraint, "Added #{@constraint.verbalise} #{@constraint.class.roles.keys.map{|k|"#{k} => "+@constraint.send(k).verbalise}*", "}"
|
|
607
482
|
super
|
|
608
483
|
end
|
|
484
|
+
|
|
485
|
+
def to_s
|
|
486
|
+
"#{super} #{@rings*','} over #{@clauses_lists.inspect}"
|
|
487
|
+
end
|
|
609
488
|
end
|
|
610
489
|
|
|
611
490
|
class ValueConstraint < Constraint
|
|
612
|
-
def initialize value_ranges, enforcement
|
|
491
|
+
def initialize value_ranges, units, enforcement
|
|
613
492
|
super nil, enforcement
|
|
614
493
|
@value_ranges = value_ranges
|
|
494
|
+
@units = units
|
|
615
495
|
end
|
|
616
496
|
|
|
617
497
|
def compile
|
|
618
498
|
@constraint = @constellation.ValueConstraint(:new)
|
|
499
|
+
$stderr.puts "REVISIT: units on value constraints are not yet processed" if @units
|
|
619
500
|
@value_ranges.each do |range|
|
|
620
501
|
min, max = Array === range ? range : [range, range]
|
|
621
502
|
v_range = @constellation.ValueRange(
|
|
@@ -627,6 +508,28 @@ module ActiveFacts
|
|
|
627
508
|
@enforcement.compile(@constellation, @constraint) if @enforcement
|
|
628
509
|
super
|
|
629
510
|
end
|
|
511
|
+
|
|
512
|
+
def vrto_s vr
|
|
513
|
+
if Array === vr
|
|
514
|
+
min = vr[0]
|
|
515
|
+
max = vr[1]
|
|
516
|
+
if Numeric === min or Numeric === max
|
|
517
|
+
infinite = 1.0/0
|
|
518
|
+
min ||= -infinite
|
|
519
|
+
max ||= infinite
|
|
520
|
+
else
|
|
521
|
+
min ||= 'MIN'
|
|
522
|
+
max ||= 'MAX'
|
|
523
|
+
end
|
|
524
|
+
Range.new(min, max)
|
|
525
|
+
else
|
|
526
|
+
vr
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def to_s
|
|
531
|
+
"#{super} to (#{@value_ranges.map{|vr| vrto_s(vr) }.inspect })#{ @units ? " in #{@units.inspect}" : ''}"
|
|
532
|
+
end
|
|
630
533
|
end
|
|
631
534
|
|
|
632
535
|
end
|