activefacts-cql 1.8.1 → 1.8.2

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +6 -5
  4. data/activefacts-cql.gemspec +4 -3
  5. data/lib/activefacts/cql/compiler.rb +29 -22
  6. data/lib/activefacts/cql/compiler/clause.rb +86 -84
  7. data/lib/activefacts/cql/compiler/constraint.rb +53 -53
  8. data/lib/activefacts/cql/compiler/entity_type.rb +28 -28
  9. data/lib/activefacts/cql/compiler/expression.rb +27 -27
  10. data/lib/activefacts/cql/compiler/fact.rb +37 -37
  11. data/lib/activefacts/cql/compiler/fact_type.rb +91 -85
  12. data/lib/activefacts/cql/compiler/informal.rb +48 -0
  13. data/lib/activefacts/cql/compiler/query.rb +52 -52
  14. data/lib/activefacts/cql/compiler/shared.rb +17 -17
  15. data/lib/activefacts/cql/compiler/value_type.rb +11 -11
  16. data/lib/activefacts/cql/parser/CQLParser.treetop +76 -56
  17. data/lib/activefacts/cql/parser/Context.treetop +15 -17
  18. data/lib/activefacts/cql/parser/Expressions.treetop +21 -21
  19. data/lib/activefacts/cql/parser/FactTypes.treetop +216 -216
  20. data/lib/activefacts/cql/parser/Language/English.treetop +136 -131
  21. data/lib/activefacts/cql/parser/Language/French.treetop +118 -118
  22. data/lib/activefacts/cql/parser/Language/Mandarin.treetop +111 -111
  23. data/lib/activefacts/cql/parser/LexicalRules.treetop +45 -45
  24. data/lib/activefacts/cql/parser/ObjectTypes.treetop +120 -120
  25. data/lib/activefacts/cql/parser/Terms.treetop +63 -63
  26. data/lib/activefacts/cql/parser/ValueTypes.treetop +71 -71
  27. data/lib/activefacts/cql/require.rb +8 -8
  28. data/lib/activefacts/cql/verbaliser.rb +88 -88
  29. data/lib/activefacts/cql/version.rb +1 -1
  30. data/lib/activefacts/input/cql.rb +7 -7
  31. metadata +12 -16
@@ -15,165 +15,165 @@ module ActiveFacts
15
15
  end
16
16
 
17
17
  rule entity_type
18
- s each?
18
+ s each?
19
19
  s term_definition_name
20
- m1:mapping_pragmas
21
- c:context_note?
20
+ m1:mapping_pragmas
21
+ c:context_note?
22
22
  sup:(basetype / subtype)
23
- &{|s|
24
- # There's an implicit type when we use an identification mode, register it:
25
- mode = s[6].identification_mode
26
- if mode
27
- input.context.object_type(s[3].value+mode, "identification mode type")
28
- input.context.object_type(s[3].value+' '+mode, "identification mode type")
29
- end
30
- true
31
- }
23
+ &{|s|
24
+ # There's an implicit type when we use an identification mode, register it:
25
+ mode = s[6].identification_mode
26
+ if mode
27
+ input.context.object_type(s[3].value+mode, "identification mode type")
28
+ input.context.object_type(s[3].value+' '+mode, "identification mode type")
29
+ end
30
+ true
31
+ }
32
32
  m2:mapping_pragmas
33
- c2:context_note?
33
+ c2:context_note?
34
34
  ec:entity_clauses?
35
35
  ';'
36
36
  {
37
- def ast
38
- name = term_definition_name.value
39
- clauses_ast = ec.empty? ? [] : ec.ast
40
- pragmas = m1.value+m2.value
41
- pragmas << 'independent' if sup.independent
42
- context_note = !c.empty? ? c.ast : (!c2.empty? ? c2.ast : nil)
43
- Compiler::EntityType.new name, sup.supers, sup.ast, pragmas, clauses_ast, context_note
44
- end
37
+ def ast
38
+ name = term_definition_name.value
39
+ clauses_ast = ec.empty? ? [] : ec.ast
40
+ pragmas = m1.value+m2.value
41
+ pragmas << 'independent' if sup.independent
42
+ context_note = !c.empty? ? c.ast : (!c2.empty? ? c2.ast : nil)
43
+ Compiler::EntityType.new name, sup.supers, sup.ast, pragmas, clauses_ast, context_note
44
+ end
45
45
  }
46
46
  end
47
47
 
48
48
  rule basetype
49
- basetype_expression
49
+ basetype_expression
50
50
  {
51
- def ast; identification.ast; end
52
- def supers; []; end
51
+ def ast; identification.ast; end
52
+ def supers; []; end
53
53
  def identification_mode; identification.mode; end
54
- def independent; !i.empty?; end
54
+ def independent; !i.empty?; end
55
55
  }
56
56
  end
57
57
 
58
58
  rule subtype
59
- subtype_expression
59
+ subtype_expression
60
60
  {
61
- def ast; ident.empty? ? nil : ident.ast; end
61
+ def ast; ident.empty? ? nil : ident.ast; end
62
62
  def supers; supertype_list.value; end
63
63
  def identification_mode; ident.empty? ? nil : ident.mode; end
64
- def independent; !i.empty?; end
64
+ def independent; !i.empty?; end
65
65
  }
66
66
  end
67
67
 
68
68
  rule supertype_list
69
69
  primary:term s alternate_supertypes:( (','/'and' !alpha) s !identified_by name:term s )*
70
70
  {
71
- def value
72
- [primary.value, *alternate_supertypes.elements.map { |sup| sup.name.value } ]
73
- end
74
- }
71
+ def value
72
+ [primary.value, *alternate_supertypes.elements.map { |sup| sup.name.value } ]
73
+ end
74
+ }
75
75
  end
76
76
 
77
77
  rule identification
78
78
  # REVISIT: Consider distinguishing "-Id" from just "Id", and not prepending the entity type name if no "-"
79
79
  identified_by its s i:(term/implicit_value_type_name) value_type_parameters
80
- r:(value_constraint enforcement)? # Reference Mode; value_constraint may be needed for the ValueType
80
+ r:(value_constraint enforcement)? # Reference Mode; value_constraint may be needed for the ValueType
81
81
  {
82
- def ast
83
- if r.empty?
84
- value_constraint = nil
85
- else
86
- value_constraint = Compiler::ValueConstraint.new(r.value_constraint.ast, r.enforcement.ast)
87
- end
88
- Compiler::ReferenceMode.new(i.value, value_constraint, value_type_parameters.values)
89
- end
82
+ def ast
83
+ if r.empty?
84
+ value_constraint = nil
85
+ else
86
+ value_constraint = Compiler::ValueConstraint.new(r.value_constraint.ast, r.enforcement.ast)
87
+ end
88
+ Compiler::ReferenceMode.new(i.value, value_constraint, value_type_parameters.values)
89
+ end
90
90
 
91
- def mode
92
- i.value
93
- end
94
- }
91
+ def mode
92
+ i.value
93
+ end
94
+ }
95
95
  /
96
96
  identified_by role_list
97
- &{|s|
98
- role_list = s[-1]
99
- forwards = role_list.ast.
100
- map do |role|
101
- next nil if role.is_a?(Compiler::Clause) # Can't forward-reference unaries
102
- next nil if role.leading_adjective or role.trailing_adjective
103
- role.term
104
- end.
105
- compact
106
- input.context.allowed_forward_terms(forwards)
107
- true
108
- }
97
+ &{|s|
98
+ role_list = s[-1]
99
+ forwards = role_list.ast.
100
+ map do |role|
101
+ next nil if role.is_a?(Compiler::Clause) # Can't forward-reference unaries
102
+ next nil if role.leading_adjective or role.trailing_adjective
103
+ role.term
104
+ end.
105
+ compact
106
+ input.context.allowed_forward_terms(forwards)
107
+ true
108
+ }
109
109
  {
110
- def ast
111
- role_list.ast
112
- end
110
+ def ast
111
+ role_list.ast
112
+ end
113
113
 
114
- def mode
115
- nil
116
- end
117
- }
114
+ def mode
115
+ nil
116
+ end
117
+ }
118
118
  end
119
119
 
120
120
  # Identified by roles... also used for constraints, beware
121
121
  rule role_list
122
- a:any? s
122
+ a:any? s
123
123
  head:term_or_unary s
124
- tail:(
125
- ( and S / ',' s )
126
- any? s
127
- term_or_unary s
128
- )*
124
+ tail:(
125
+ ( and S / ',' s )
126
+ any? s
127
+ term_or_unary s
128
+ )*
129
129
  {
130
- def ast
131
- [head.ast, *tail.elements.map{|e| e.term_or_unary.ast}]
132
- end
130
+ def ast
131
+ [head.ast, *tail.elements.map{|e| e.term_or_unary.ast}]
132
+ end
133
133
  }
134
134
  end
135
135
 
136
136
  rule unary_text
137
- (s !any !non_phrase !term id)*
138
- {
139
- def node_type; :linking; end
140
- }
137
+ (s !any !non_phrase !term id)*
138
+ {
139
+ def node_type; :linking; end
140
+ }
141
141
  end
142
142
 
143
143
  rule term_or_unary
144
- pre_text:unary_text s term post_text:unary_text s ss:subscript?
145
- {
146
- def ast
147
- t = term.ast
148
- t.role_name = ss.value if !ss.empty?
149
- if pre_text.elements.size == 0 && post_text.elements.size == 0
150
- t
151
- else
152
- pre_words = pre_text.elements.map{|w| w.id.text_value}
153
- post_words = post_text.elements.map{|w| w.id.text_value}
154
- Compiler::Clause.new(pre_words + [t] + post_words, [], nil)
155
- end
156
- end
157
- }
158
- /
159
- s !non_phrase id s &non_phrase s ss:subscript?
160
- { # A forward-referenced entity type
161
- # REVISIT: A change in this rule might allow forward-referencing a multi-word term
162
- def ast
163
- Compiler::Reference.new(id.text_value, nil, nil, nil, nil, ss.empty? ? nil : ss.value)
164
- end
165
- }
144
+ pre_text:unary_text s term post_text:unary_text s ss:subscript?
145
+ {
146
+ def ast
147
+ t = term.ast
148
+ t.role_name = ss.value if !ss.empty?
149
+ if pre_text.elements.size == 0 && post_text.elements.size == 0
150
+ t
151
+ else
152
+ pre_words = pre_text.elements.map{|w| w.id.text_value}
153
+ post_words = post_text.elements.map{|w| w.id.text_value}
154
+ Compiler::Clause.new(pre_words + [t] + post_words, [], nil)
155
+ end
156
+ end
157
+ }
158
+ /
159
+ s !non_phrase id s &non_phrase s ss:subscript?
160
+ { # A forward-referenced entity type
161
+ # REVISIT: A change in this rule might allow forward-referencing a multi-word term
162
+ def ast
163
+ Compiler::Reference.new(id.text_value, nil, nil, nil, nil, ss.empty? ? nil : ss.value)
164
+ end
165
+ }
166
166
  end
167
167
 
168
168
  rule mapping_pragmas
169
169
  '[' s h:mapping_pragma t:(s ',' s mapping_pragma)* s ']' s
170
170
  {
171
- def value
172
- t.elements.inject([h.value*' ']) do |a, e|
173
- a << e.mapping_pragma.value*' '
174
- end
175
- end
176
- }
171
+ def value
172
+ t.elements.inject([h.value*' ']) do |a, e|
173
+ a << e.mapping_pragma.value*' '
174
+ end
175
+ end
176
+ }
177
177
  /
178
178
  s
179
179
  { def value; []; end }
@@ -181,27 +181,27 @@ module ActiveFacts
181
181
 
182
182
  # Each mapping_pragma returns an array of words
183
183
  rule mapping_pragma
184
- was s names:(id s)+
185
- { # Old or previous name of an object type:
186
- def value
187
- [ was.text_value ] + names.elements.map{|n|n.text_value}
188
- end
189
- }
190
- /
191
- head:id tail:(s id)*
192
- { # A sequence of one or more words denoting a pragma:
193
- def value
194
- ([head]+tail.elements.map(&:id)).map(&:text_value)
195
- end
196
- }
184
+ was s names:(id s)+
185
+ { # Old or previous name of an object type:
186
+ def value
187
+ [ was.text_value ] + names.elements.map{|n|n.text_value}
188
+ end
189
+ }
190
+ /
191
+ head:id tail:(s id)*
192
+ { # A sequence of one or more words denoting a pragma:
193
+ def value
194
+ ([head]+tail.elements.map(&:id)).map(&:text_value)
195
+ end
196
+ }
197
197
  end
198
198
 
199
199
  rule entity_clauses
200
200
  (':' / where) s query_clauses
201
201
  {
202
- def ast
202
+ def ast
203
203
  query_clauses.ast
204
- end
204
+ end
205
205
  }
206
206
  end
207
207
 
@@ -9,47 +9,47 @@ module ActiveFacts
9
9
  grammar Terms
10
10
  rule term_definition_name
11
11
  id s t:(!non_term_def id s)*
12
- <Parser::TermDefinitionNameNode>
12
+ <Parser::TermDefinitionNameNode>
13
13
  end
14
14
 
15
15
  rule non_term_def
16
16
  mapping_pragmas entity_prefix
17
- / mapping_pragmas written_as # Value type
18
- / mapping_pragmas is_where # Objectified type
17
+ / mapping_pragmas written_as # Value type
18
+ / mapping_pragmas is_where # Objectified type
19
19
  / non_phrase
20
- / identified_by # as in: "a kind of X identified by..."
21
- / in_units
22
- / auto_assignment
23
- / value_constraint
20
+ / identified_by # as in: "a kind of X identified by..."
21
+ / in_units
22
+ / auto_assignment
23
+ / value_constraint
24
24
  end
25
25
 
26
26
  rule entity_prefix
27
27
  is s (independent s )? identified_by
28
- /
29
- subtype_prefix (independent s )? term_definition_name
30
- &{|e| input.context.object_type(e[2].value, "subtype") }
28
+ /
29
+ subtype_prefix (independent s )? term_definition_name
30
+ &{|e| input.context.object_type(e[2].value, "subtype") }
31
31
  end
32
32
 
33
33
  rule prescan
34
34
  s each?
35
- s (
35
+ s (
36
36
  term_definition_name mapping_pragmas entity_prefix
37
- &{|e| input.context.object_type(e[0].value, "entity type") }
37
+ &{|e| input.context.object_type(e[0].value, "entity type") }
38
38
  /
39
39
  t1:term_definition_name mapping_pragmas written_as any? s t2:term_definition_name
40
40
  &{|e|
41
- new_term = e[0].value
42
- input.context.object_type(new_term, "value type")
43
- base_term = e[5].value
44
- input.context.object_type(base_term, "value type")
45
- }
41
+ new_term = e[0].value
42
+ input.context.object_type(new_term, "value type")
43
+ base_term = e[5].value
44
+ input.context.object_type(base_term, "value type")
45
+ }
46
46
  /
47
47
  term_definition_name s mapping_pragmas is_where
48
48
  &{|e| input.context.object_type(e[0].value, "objectified_fact_type") }
49
49
  )?
50
50
  prescan_rest
51
51
  &{|s|
52
- # Wipe any terminal failures that were added:
52
+ # Wipe any terminal failures that were added:
53
53
  @terminal_failures = []
54
54
  @max_terminal_failure_index = start_index
55
55
 
@@ -66,13 +66,13 @@ module ActiveFacts
66
66
  context_note # Context notes have different lexical conventions
67
67
  / '(' as S term_definition_name s ')' s # Prepare for a Role Name
68
68
  &{|s| input.context.role_name(s[3].value) }
69
- / new_derived_value # Prepare for a derived term
70
- / new_adjective_term # Prepare for an existing term with new Adjectives
71
- # The remaining rules exist to correctly eat up anything that doesn't match the above:
69
+ / new_derived_value # Prepare for a derived term
70
+ / new_adjective_term # Prepare for an existing term with new Adjectives
71
+ # The remaining rules exist to correctly eat up anything that doesn't match the above:
72
72
  / global_term # If we see A B - C D, don't recognise B as a new adjective for C D.
73
- / prescan_aggregate
73
+ / prescan_aggregate
74
74
  / id
75
- # / literal # REVISIT: Literals might contain "(as Foo)" and mess things up
75
+ # / literal # REVISIT: Literals might contain "(as Foo)" and mess things up
76
76
  / range # Covers all numbers and strings
77
77
  / comparator # handle two-character operators
78
78
  / S # White space and comments, must precede / and *
@@ -82,75 +82,75 @@ module ActiveFacts
82
82
 
83
83
  # Not sure this is even needed, but it doesn't seem to hurt:
84
84
  rule prescan_aggregate
85
- aggregate_type:id s agg_of s global_term agg_in s &'('
85
+ aggregate_type:id s agg_of s global_term agg_in s &'('
86
86
  end
87
87
 
88
88
  rule new_derived_value
89
89
  !global_term id derived_value_continuation? s '='
90
- &{|s|
91
- name = [s[1].text_value] + (s[2].empty? ? [] : s[2].value)
92
- input.context.object_type(name*' ', "derived value type")
93
- }
94
- /
95
- '=' s !global_term id derived_value_continuation? s (that/who)
96
- &{|s|
97
- name = [s[3].text_value] + (s[4].empty? ? [] : s[4].value)
98
- input.context.object_type(name*' ', "derived value type")
99
- }
90
+ &{|s|
91
+ name = [s[1].text_value] + (s[2].empty? ? [] : s[2].value)
92
+ input.context.object_type(name*' ', "derived value type")
93
+ }
94
+ /
95
+ '=' s !global_term id derived_value_continuation? s (that/who)
96
+ &{|s|
97
+ name = [s[3].text_value] + (s[4].empty? ? [] : s[4].value)
98
+ input.context.object_type(name*' ', "derived value type")
99
+ }
100
100
  end
101
101
 
102
102
  # Derived values are new terms introduced by an = sign before an expression
103
103
  # This rule handles trailing words of a multi-word derived value
104
104
  rule derived_value_continuation
105
105
  s '-' tail:(s !global_term !(that/who) id)*
106
- {
107
- def value
108
- tail.elements.map{|e| e.id.text_value}
109
- end
110
- }
106
+ {
107
+ def value
108
+ tail.elements.map{|e| e.id.text_value}
109
+ end
110
+ }
111
111
  end
112
112
 
113
113
  # Used during the pre-scan, match a term with new adjective(s)
114
114
  rule new_adjective_term
115
- !global_term adj:id '-' '-'? lead_intervening s global_term # Definitely a new leading adjective for this term
115
+ !global_term adj:id '-' '-'? lead_intervening s global_term # Definitely a new leading adjective for this term
116
116
  &{|s| adj = [s[1].text_value, s[4].value].compact*" "; input.context.new_leading_adjective_term(adj, s[6].text_value) }
117
117
  /
118
- global_term s trail_intervening '-' '-'? !global_term adj:id # Definitely a new trailing adjective for this term
118
+ global_term s trail_intervening '-' '-'? !global_term adj:id # Definitely a new trailing adjective for this term
119
119
  &{|s| adj = [s[2].value, s[6].text_value].compact*" "; input.context.new_trailing_adjective_term(adj, s[0].text_value) }
120
120
  end
121
121
 
122
- rule lead_intervening # Words intervening between a new adjective and the term
123
- (S !global_term id)*
124
- {
125
- def value
126
- elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
127
- end
128
- }
122
+ rule lead_intervening # Words intervening between a new adjective and the term
123
+ (S !global_term id)*
124
+ {
125
+ def value
126
+ elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
127
+ end
128
+ }
129
129
  end
130
130
 
131
- rule trail_intervening # Words intervening between a new adjective and the term
132
- (!global_term id S)*
133
- {
134
- def value
135
- elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
136
- end
137
- }
131
+ rule trail_intervening # Words intervening between a new adjective and the term
132
+ (!global_term id S)*
133
+ {
134
+ def value
135
+ elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
136
+ end
137
+ }
138
138
  end
139
139
 
140
140
  # This is the rule to use after the prescan; it only succeeds on a complete term or role reference
141
141
  rule term
142
- s head:id x &{|s| w = s[1].text_value; input.context.term_starts?(w, s[2]) }
142
+ s head:id x &{|s| w = s[1].text_value; input.context.term_starts?(w, s[2]) }
143
143
  tail:(
144
- s '-'? dbl:'-'? s w:id &{|s| w = s[4].text_value; input.context.term_continues?(w) }
145
- )* &{|s| input.context.term_complete? }
146
- <Parser::TermNode>
147
- /
148
- s head:id '-' '-'? s term &{|s| s[5].ast.leading_adjective == nil }
149
- <Parser::TermLANode>
144
+ s '-'? dbl:'-'? s w:id &{|s| w = s[4].text_value; input.context.term_continues?(w) }
145
+ )* &{|s| input.context.term_complete? }
146
+ <Parser::TermNode>
147
+ /
148
+ s head:id '-' '-'? s term &{|s| s[5].ast.leading_adjective == nil }
149
+ <Parser::TermLANode>
150
150
  end
151
151
 
152
152
  rule x
153
- '' <SavedContext>
153
+ '' <SavedContext>
154
154
  end
155
155
 
156
156
  rule global_term