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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +6 -5
- data/activefacts-cql.gemspec +4 -3
- data/lib/activefacts/cql/compiler.rb +29 -22
- data/lib/activefacts/cql/compiler/clause.rb +86 -84
- data/lib/activefacts/cql/compiler/constraint.rb +53 -53
- data/lib/activefacts/cql/compiler/entity_type.rb +28 -28
- data/lib/activefacts/cql/compiler/expression.rb +27 -27
- data/lib/activefacts/cql/compiler/fact.rb +37 -37
- data/lib/activefacts/cql/compiler/fact_type.rb +91 -85
- data/lib/activefacts/cql/compiler/informal.rb +48 -0
- data/lib/activefacts/cql/compiler/query.rb +52 -52
- data/lib/activefacts/cql/compiler/shared.rb +17 -17
- data/lib/activefacts/cql/compiler/value_type.rb +11 -11
- data/lib/activefacts/cql/parser/CQLParser.treetop +76 -56
- data/lib/activefacts/cql/parser/Context.treetop +15 -17
- data/lib/activefacts/cql/parser/Expressions.treetop +21 -21
- data/lib/activefacts/cql/parser/FactTypes.treetop +216 -216
- data/lib/activefacts/cql/parser/Language/English.treetop +136 -131
- data/lib/activefacts/cql/parser/Language/French.treetop +118 -118
- data/lib/activefacts/cql/parser/Language/Mandarin.treetop +111 -111
- data/lib/activefacts/cql/parser/LexicalRules.treetop +45 -45
- data/lib/activefacts/cql/parser/ObjectTypes.treetop +120 -120
- data/lib/activefacts/cql/parser/Terms.treetop +63 -63
- data/lib/activefacts/cql/parser/ValueTypes.treetop +71 -71
- data/lib/activefacts/cql/require.rb +8 -8
- data/lib/activefacts/cql/verbaliser.rb +88 -88
- data/lib/activefacts/cql/version.rb +1 -1
- data/lib/activefacts/input/cql.rb +7 -7
- metadata +12 -16
@@ -15,165 +15,165 @@ module ActiveFacts
|
|
15
15
|
end
|
16
16
|
|
17
17
|
rule entity_type
|
18
|
-
|
18
|
+
s each?
|
19
19
|
s term_definition_name
|
20
|
-
|
21
|
-
|
20
|
+
m1:mapping_pragmas
|
21
|
+
c:context_note?
|
22
22
|
sup:(basetype / subtype)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
33
|
+
c2:context_note?
|
34
34
|
ec:entity_clauses?
|
35
35
|
';'
|
36
36
|
{
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
49
|
+
basetype_expression
|
50
50
|
{
|
51
|
-
|
52
|
-
|
51
|
+
def ast; identification.ast; end
|
52
|
+
def supers; []; end
|
53
53
|
def identification_mode; identification.mode; end
|
54
|
-
|
54
|
+
def independent; !i.empty?; end
|
55
55
|
}
|
56
56
|
end
|
57
57
|
|
58
58
|
rule subtype
|
59
|
-
|
59
|
+
subtype_expression
|
60
60
|
{
|
61
|
-
|
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
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
80
|
+
r:(value_constraint enforcement)? # Reference Mode; value_constraint may be needed for the ValueType
|
81
81
|
{
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
def mode
|
92
|
+
i.value
|
93
|
+
end
|
94
|
+
}
|
95
95
|
/
|
96
96
|
identified_by role_list
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
110
|
+
def ast
|
111
|
+
role_list.ast
|
112
|
+
end
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
122
|
+
a:any? s
|
123
123
|
head:term_or_unary s
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
tail:(
|
125
|
+
( and S / ',' s )
|
126
|
+
any? s
|
127
|
+
term_or_unary s
|
128
|
+
)*
|
129
129
|
{
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
-
|
202
|
+
def ast
|
203
203
|
query_clauses.ast
|
204
|
-
|
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
|
-
|
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
|
18
|
-
/ mapping_pragmas is_where
|
17
|
+
/ mapping_pragmas written_as # Value type
|
18
|
+
/ mapping_pragmas is_where # Objectified type
|
19
19
|
/ non_phrase
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
35
|
+
s (
|
36
36
|
term_definition_name mapping_pragmas entity_prefix
|
37
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|
-
|
70
|
-
/ new_adjective_term
|
71
|
-
|
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
|
-
|
73
|
+
/ prescan_aggregate
|
74
74
|
/ id
|
75
|
-
|
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
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
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
|
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
|
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
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
142
|
+
s head:id x &{|s| w = s[1].text_value; input.context.term_starts?(w, s[2]) }
|
143
143
|
tail:(
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
153
|
+
'' <SavedContext>
|
154
154
|
end
|
155
155
|
|
156
156
|
rule global_term
|