activefacts-cql 1.9.6 → 1.9.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,197 +0,0 @@
1
- #
2
- # ActiveFacts CQL Parser.
3
- # Parse rules relating to Term names
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module CQL
9
- grammar Terms
10
- rule term_definition_name
11
- id s t:(!non_term_def id s)*
12
- <Parser::TermDefinitionNameNode>
13
- end
14
-
15
- rule non_term_def
16
- mapping_pragmas entity_prefix
17
- / mapping_pragmas written_as # Value type
18
- / mapping_pragmas is_where # Objectified type
19
- / non_phrase
20
- / identified_by # as in: "a kind of X identified by..."
21
- / in_units
22
- / auto_assignment
23
- / value_constraint
24
- end
25
-
26
- rule entity_prefix
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") }
31
- end
32
-
33
- rule prescan
34
- informally_prescan
35
- /
36
- s each?
37
- s (
38
- term_definition_name mapping_pragmas entity_prefix
39
- &{|e| input.context.object_type(e[0].value, "entity type") }
40
- /
41
- t1:term_definition_name mapping_pragmas written_as any? s t2:term_definition_name
42
- &{|e|
43
- new_term = e[0].value
44
- input.context.object_type(new_term, "value type")
45
- base_term = e[5].value
46
- input.context.object_type(base_term, "value type")
47
- }
48
- /
49
- term_definition_name s mapping_pragmas is_where
50
- &{|e| input.context.object_type(e[0].value, "objectified_fact_type") }
51
- )?
52
- prescan_rest
53
- &{|s|
54
- # Wipe any terminal failures that were added:
55
- forget_failures_to_here
56
-
57
- # puts "========== prescan is complete on #{(s.map{|e|e.text_value}*" ").inspect} =========="
58
- false
59
- }
60
- end
61
-
62
- rule informally_prescan
63
- informally s ',' s
64
- informal_description_subject_prescan s
65
- informal_description_body
66
- informal_description_closer
67
- end
68
-
69
- rule informal_description_subject_prescan
70
- each S term_definition_name # Informal definition of an object type
71
- /
72
- when S phrase+ s ',' # or a fact type; we can't forward-reference these
73
- # This could memoize a bad parse for 'phrase'!!!
74
- end
75
-
76
- # Do a first-pass mainly lexical analysis, looking for role name definitions and adjectives,
77
- # for use in detecting terms later.
78
- rule prescan_rest
79
- &{|s| input.context.reset_role_names }
80
- (
81
- context_note # Context notes have different lexical conventions
82
- / '(' as S term_definition_name s ')' s # Prepare for a Role Name
83
- &{|s| input.context.role_name(s[3].value) }
84
- / new_derived_value # Prepare for a derived term
85
- / new_adjective_term # Prepare for an existing term with new Adjectives
86
- # The remaining rules exist to correctly eat up anything that doesn't match the above:
87
- / global_term # If we see A B - C D, don't recognise B as a new adjective for C D.
88
- / prescan_aggregate
89
- / id
90
- # / literal # REVISIT: Literals might contain "(as Foo)" and mess things up
91
- / range # Covers all numbers and strings
92
- / S # White space and comments, must precede / and *
93
- / [^;] # Skip anything else, we want the prescan to finish
94
- )* [?;] s
95
- end
96
-
97
- # Not sure this is even needed, but it doesn't seem to hurt:
98
- rule prescan_aggregate
99
- aggregate_type:id s agg_of s global_term agg_in s &'('
100
- end
101
-
102
- rule new_derived_value
103
- !global_term id derived_value_continuation? s '='
104
- &{|s|
105
- name = [s[1].text_value] + (s[2].empty? ? [] : s[2].value)
106
- input.context.object_type(name*' ', "derived value type")
107
- }
108
- /
109
- '=' s !global_term id derived_value_continuation? s (that/who)
110
- &{|s|
111
- name = [s[3].text_value] + (s[4].empty? ? [] : s[4].value)
112
- input.context.object_type(name*' ', "derived value type")
113
- }
114
- end
115
-
116
- # Derived values are new terms introduced by an = sign before an expression
117
- # This rule handles trailing words of a multi-word derived value
118
- rule derived_value_continuation
119
- s '-' tail:(s !global_term !(that/who) id)*
120
- {
121
- def value
122
- tail.elements.map{|e| e.id.text_value}
123
- end
124
- }
125
- end
126
-
127
- # Used during the pre-scan, match a term with new adjective(s)
128
- rule new_adjective_term
129
- !global_term adj:id '-' '-'? lead_intervening s global_term # Definitely a new leading adjective for this term
130
- &{|s| adj = [s[1].text_value, s[4].value].compact*" "; input.context.new_leading_adjective_term(adj, s[6].text_value) }
131
- /
132
- global_term s trail_intervening '-' '-'? !global_term adj:id # Definitely a new trailing adjective for this term
133
- &{|s| adj = [s[2].value, s[6].text_value].compact*" "; input.context.new_trailing_adjective_term(adj, s[0].text_value) }
134
- end
135
-
136
- rule lead_intervening # Words intervening between a new adjective and the term
137
- (S !global_term id)*
138
- {
139
- def value
140
- elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
141
- end
142
- }
143
- end
144
-
145
- rule trail_intervening # Words intervening between a new adjective and the term
146
- (!global_term id S)*
147
- {
148
- def value
149
- elements.size == 0 ? nil : elements.map{|e| e.id.text_value}*" "
150
- end
151
- }
152
- end
153
-
154
- # This is the rule to use after the prescan; it only succeeds on a complete term or role reference
155
- rule term
156
- s head:id x &{|s| w = s[1].text_value; input.context.term_starts?(w, s[2]) }
157
- tail:(
158
- s '-'? dbl:'-'? s w:id &{|s| w = s[4].text_value; input.context.term_continues?(w) }
159
- )* &{|s| input.context.term_complete? }
160
- <Parser::TermNode>
161
- /
162
- s head:id '-' '-'? s term &{|s| s[5].ast.leading_adjective == nil }
163
- <Parser::TermLANode>
164
- end
165
-
166
- rule x
167
- '' <SavedContext>
168
- end
169
-
170
- rule global_term
171
- # This rule shouldn't be used outside the prescan, it will memoize the wrong things.
172
- head:id x &{|s| input.context.global_term_starts?(s[0].text_value, s[1]) }
173
- tail:(s w:id &{|s| input.context.global_term_continues?(s[1].text_value) } )*
174
- { def value
175
- tail.elements.inject(head.value) { |t, e| "#{t} #{e.w.value}" }
176
- end
177
- }
178
- end
179
-
180
- rule non_phrase
181
- # These words are illegal in (but maybe ok following) a clause where a phrase is expected:
182
- and
183
- / but
184
- / if
185
- / role_list_constraint_followers
186
- / only_if
187
- / or
188
- / quantifier
189
- / returning
190
- / then
191
- / value_constraint
192
- / where
193
- end
194
-
195
- end
196
- end
197
- end
@@ -1,226 +0,0 @@
1
- #
2
- # ActiveFacts CQL Parser.
3
- # Parse rules relating to Transformation Rules.
4
- #
5
- # Copyright (c) 2017 Factil Pty Ltd. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module CQL
9
- grammar TransformRules
10
-
11
- rule transform_rule
12
- ctr:compound_matching s ';'
13
- {
14
- def ast
15
- Compiler::TransformRule.new(ctr.ast)
16
- end
17
- }
18
- end
19
-
20
- rule compound_matching
21
- s tl:term_list s '<==' s tq:transform_query? s '{' tr:transform_matchings s '}'
22
- {
23
- def ast
24
- Compiler::CompoundMatching.new(tl.ast, tq.empty? ? nil : tq.ast, tr.ast)
25
- end
26
- }
27
- end
28
-
29
- rule simple_matching
30
- s tl:term_list s '<--' s te:transform_expr?
31
- {
32
- def ast
33
- Compiler::SimpleMatching.new(tl.ast, te.empty? ? nil : te.ast)
34
- end
35
- }
36
- end
37
-
38
- rule transform_query
39
- cl:clauses_list { def ast; cl.ast; end; }
40
- / t:term { def ast; t.ast; end; }
41
- end
42
-
43
- rule transform_matchings
44
- s r0:transform_matching tail:(s ',' s r1:transform_matching)*
45
- {
46
- def ast
47
- [r0.ast, *tail.elements.map{|e| e.r1.ast }]
48
- end
49
- }
50
- end
51
-
52
- rule transform_matching
53
- str:simple_matching { def ast; str.ast; end; }
54
- / ctr:compound_matching { def ast; ctr.ast; end; }
55
- end
56
-
57
- rule term_list
58
- s t0:term tail:(s '.' s t1:term_list)*
59
- {
60
- def ast
61
- if tail.elements.empty?
62
- [t0.ast]
63
- else
64
- [t0.ast, *tail.elements.map{|t| t.t1.ast }]
65
- end
66
- end
67
- }
68
- end
69
-
70
- rule transform_expr
71
- s c:logical_texpr s '?' s t0:logical_texpr s ':' s t1:logical_texpr
72
- {
73
- def ast
74
- Compiler::Ternary.new(c.ast, t0.ast, t1.ast)
75
- end
76
- }
77
- / s o:aggregate_op S agg_of s t:logical_texpr
78
- {
79
- def ast
80
- Compiler::Aggregate.new(o.text_value, t.ast)
81
- end
82
- }
83
- / s t0:logical_texpr { def ast; t0.ast; end; }
84
- end
85
-
86
- rule aggregate_op
87
- 'sum' / 'average' / 'max' / 'min' / 'count'
88
- end
89
-
90
- rule logical_texpr
91
- s t0:logical_and_texpr tail:(s op:or s t1:logical_and_texpr)*
92
- {
93
- def ast
94
- if tail.elements.empty?
95
- t0.ast
96
- else
97
- Compiler::LogicalOr.new(t0.ast, *tail.elements.map{|e| e.t1.ast})
98
- end
99
- end
100
- }
101
- end
102
-
103
- rule logical_and_texpr
104
- s t0:equality_texpr tail:(s op:and s t1:equality_texpr)*
105
- {
106
- def ast
107
- if tail.elements.empty?
108
- t0.ast
109
- else
110
- Compiler::LogicalAnd.new(t0.ast, *tail.elements.map{|e| e.t1.ast})
111
- end
112
- end
113
- }
114
- end
115
-
116
- rule equality_texpr
117
- s t0:relational_texpr operation:(s op:equality_op s t1:relational_texpr)?
118
- {
119
- def ast
120
- if operation.empty?
121
- t0.ast
122
- else
123
- Compiler::Comparison.new(op.text_value, t0.ast, operation.t1.ast)
124
- end
125
- end
126
- }
127
- end
128
-
129
- rule equality_op
130
- '=' / '!='
131
- end
132
-
133
- rule relational_texpr
134
- s t0:additive_texpr operation:(s op:relational_op s t1:additive_texpr)?
135
- {
136
- def ast
137
- if operation.empty?
138
- t0.ast
139
- else
140
- Compiler::Comparison.new(op.text_value, t0.ast, operation.t1.ast)
141
- end
142
- end
143
- }
144
- end
145
-
146
- rule relational_op
147
- '<' / '>' / '>=' / '<='
148
- end
149
-
150
- rule additive_texpr
151
- s t0:multiplicative_texpr tail:(s op:additive_op s t1:multiplicative_texpr)*
152
- {
153
- def ast
154
- if tail.elements.empty?
155
- t0.ast
156
- else
157
- Compiler::Sum.new(
158
- t0.ast,
159
- *tail.elements.map{|e| e.op.text_value == '-' ? Compiler::Negate.new(e.t1.ast) : e.t1.ast}
160
- )
161
- end
162
- end
163
- }
164
- end
165
-
166
- rule additive_op
167
- '+' / '-'
168
- end
169
-
170
- rule multiplicative_texpr
171
- s t0:unary_texpr tail:(s op:multiplicative_op s t1:unary_texpr)*
172
- {
173
- def ast
174
- if tail.elements.empty?
175
- t0.ast
176
- else
177
- Compiler::Product.new(
178
- t0.ast,
179
- *tail.elements.map{|e| e.op.text_value == '/' ? Compiler::Reciprocal.new(e.t1.ast) : e.t1.ast}
180
- )
181
- end
182
- end
183
- }
184
- end
185
-
186
- rule multiplicative_op
187
- '*' / '/'
188
- end
189
-
190
- rule unary_texpr
191
- s u:unary_op? s t:primary_texpr
192
- {
193
- def ast
194
- if u.empty?
195
- t.ast
196
- else
197
- u.text_value == '-' ? Compiler::Negate.new(t.ast) : Compiler::Negation.new(t.ast)
198
- end
199
- end
200
- }
201
- end
202
-
203
- rule unary_op
204
- '-' / '!'
205
- end
206
-
207
- rule primary_texpr
208
- tl:term_list
209
- {
210
- def ast
211
- Compiler::ExpressionTermList.new(tl.ast)
212
- end
213
- }
214
- / l:literal
215
- {
216
- def ast
217
- Compiler::Literal.new(l.value, nil)
218
- end
219
- }
220
- # / '(' source_expr ')'
221
- # / id '(' source_expr (s ',' s source_expr) * ')'
222
- end
223
-
224
- end
225
- end
226
- end
@@ -1,244 +0,0 @@
1
- #
2
- # ActiveFacts CQL Parser.
3
- # Parse rules relating to ValueType definitions.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- module ActiveFacts
8
- module CQL
9
- grammar ValueTypes
10
- rule value_type
11
- s each?
12
- s term_definition_name
13
- m1:mapping_pragmas
14
- # REVISIT: ORM2 would allow (subtype_prefix term)?
15
- written_as
16
- any? s
17
- base:(term/implicit_value_type_name) s
18
- value_type_parameters
19
- u:in_units?
20
- a:auto_assignment?
21
- c:context_note?
22
- r:(value_constraint enforcement)?
23
- m2:mapping_pragmas
24
- c2:context_note?
25
- s ';' s
26
- {
27
- def ast
28
- name = term_definition_name.value
29
- params = value_type_parameters.values
30
- value_constraint = nil
31
- unless r.empty?
32
- value_constraint = Compiler::ValueConstraint.new(r.value_constraint.ast, r.enforcement.ast)
33
- end
34
- units = u.empty? ? [] : u.units.value
35
- auto_assigned_at = a.empty? ? nil : a.auto_assigned_at
36
- pragmas = m1.value+m2.value
37
- context_note = !c.empty? ? c.ast : (!c2.empty? ? c2.ast : nil)
38
- Compiler::ValueType.new name, base.value, params, units, value_constraint, pragmas, context_note, auto_assigned_at
39
- end
40
- }
41
- end
42
-
43
- rule in_units
44
- in S units
45
- end
46
-
47
- # A ValueType name that might not yet have been identified or registered as a Term
48
- # REVISIT: We'd like to support multi-word terms here (cannot include "where", "and", or anything that could follow in the value_type definition)
49
- # REVISIT: We'd like these to be forward-referenced ObjectTypes too, not immediately created as ValueTypes
50
- rule implicit_value_type_name
51
- id
52
- {
53
- def node_type; :term; end
54
- }
55
- end
56
-
57
- rule value_type_parameters
58
- '(' s tpl:type_parameter_list? ')' s
59
- { def values; tpl.empty? ? [] : tpl.values; end }
60
- / s
61
- { def values; []; end }
62
- end
63
-
64
- rule type_parameter_list
65
- head:parameter s tail:( ',' s parameter s)*
66
- {
67
- def values
68
- [head.value, *tail.elements.map{|i| i.parameter.value}]
69
- end
70
- }
71
- end
72
-
73
- rule parameter
74
- number / named_parameter
75
- end
76
-
77
- rule ordered_parameter
78
- number
79
- end
80
-
81
- rule named_parameter
82
- ( # Set the value for a parameter
83
- with s parameter_name as s literal:parameter_literal
84
- /
85
- parameter_name ':' s literal:parameter_literal
86
- ) <Parser::ValueTypeParameterSetting>
87
- / # Define a new parameter
88
- accepts s parameter_name as value_type:term s vr:(restricted s to s parameter_restriction)? <Parser::ValueTypeParameterDefinition>
89
- / # Restrict values for a parameter
90
- restricts s parameter_name to s parameter_restriction <Parser::ValueTypeParameterRestriction>
91
- end
92
-
93
- rule parameter_name
94
- !(with/accepts/restricts/as/term) id s
95
- { def value; id.text_value; end }
96
- end
97
-
98
- rule parameter_literal
99
- number
100
- / # We need the text_value of a string here, not the result of parsing it
101
- string { def value; text_value; end }
102
- end
103
-
104
- rule parameter_restriction
105
- range_list s
106
- { def values; range_list.ranges; end}
107
- /
108
- parameter_literal s direction:(min / max)? s
109
- { def values; [:value, parameter_literal.value, direction.text_value]; end}
110
- end
111
-
112
- rule unit_definition
113
- u:(
114
- s coeff:unit_coefficient? base:units? s o:unit_offset?
115
- conversion
116
- singular:unit_name s plural:('/' s p:unit_name s)?
117
- /
118
- s singular:unit_name s plural:('/' s p:unit_name s)?
119
- conversion
120
- coeff:unit_coefficient? base:units? s o:unit_offset?
121
- )
122
- q:(approximately '' / ephemera s url )? s
123
- ';'
124
- {
125
- def ast
126
- singular = u.singular.text_value
127
- plural = u.plural.text_value.empty? ? nil : u.plural.p.text_value
128
- if u.coeff.empty?
129
- raise "Unit definition requires either a coefficient or an ephemera URL" unless q.respond_to?(:ephemera)
130
- numerator,denominator = 1, 1
131
- else
132
- numerator, denominator = *u.coeff.ast
133
- end
134
- offset = u.o.text_value.empty? ? 0 : u.o.value
135
- bases = u.base.empty? ? [] : u.base.value
136
- approximately = q.respond_to?(:approximately) || u.conversion.approximate?
137
- ephemera = q.respond_to?(:ephemera) ? q.url.text_value : nil
138
- Compiler::Unit.new singular, plural, numerator, denominator, offset, bases, approximately, ephemera
139
- end
140
- }
141
- end
142
-
143
- rule unit_name
144
- id
145
- {
146
- def node_type; :unit; end
147
- }
148
- end
149
-
150
-
151
- rule unit_coefficient
152
- numerator:number denominator:(s '/' s number)? s
153
- {
154
- def ast
155
- [ numerator.text_value,
156
- (denominator.text_value.empty? ? "1" : denominator.number.text_value)
157
- ]
158
- end
159
- }
160
- end
161
-
162
- rule unit_offset
163
- sign:[-+] s number s
164
- { def value
165
- sign.text_value == '-' ? "-"+number.text_value : number.text_value
166
- end
167
- }
168
- end
169
-
170
- # In a unit definition, we may use undefined base units; this is the only way to get fundamental units
171
- rule units
172
- !non_unit maybe_unit s tail:(!non_unit maybe_unit s)* div:('/' s maybe_unit s tail:(!non_unit maybe_unit s)*)?
173
- { def value
174
- tail.elements.inject([maybe_unit.value]) { |a, e| a << e.maybe_unit.value } +
175
- (div.text_value.empty? ? [] : div.tail.elements.inject([div.maybe_unit.inverse]) { |a, e| a << e.maybe_unit.inverse })
176
- end
177
- }
178
- end
179
-
180
- rule non_unit
181
- restricted_to / conversion / approximately / ephemera / auto_assignment
182
- end
183
-
184
- rule unit
185
- maybe_unit &{|s| input.context.unit?(s[0].unit_name.text_value) }
186
- end
187
-
188
- rule maybe_unit
189
- unit_name pow:('^' '-'? [0-9])?
190
- { def value
191
- [unit_name.text_value, pow.text_value.empty? ? 1 : Integer(pow.text_value[1..-1])]
192
- end
193
- def inverse
194
- a = value
195
- a[1] = -a[1]
196
- a
197
- end
198
- }
199
- end
200
-
201
- rule value_constraint
202
- restricted_to restricted_values c:context_note?
203
- {
204
- def ast
205
- v = restricted_values.values
206
- c[:context_note] = c.ast unless c.empty?
207
- v
208
- end
209
- }
210
- # REVISIT: "where the possible value/s of that <Term> is/are value (, ...)"
211
- end
212
-
213
- rule restricted_values
214
- range_list s u:units?
215
- {
216
- def values
217
- { :ranges => range_list.ranges,
218
- :units => u.empty? ? nil : u.value
219
- }
220
- end
221
- }
222
- /
223
- regular_expression
224
- {
225
- def values
226
- { :regular_expression => contents }
227
- end
228
- }
229
- end
230
-
231
- rule range_list
232
- '{' s
233
- head:range s tail:( ',' s range )*
234
- '}' s
235
- {
236
- def ranges
237
- [head.value, *tail.elements.map{|e| e.range.value }]
238
- end
239
- }
240
- end
241
-
242
- end
243
- end
244
- end