activefacts 1.6.0 → 1.7.1
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 +14 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +3 -80
- data/activefacts.gemspec +36 -0
- data/bin/afgen +4 -2
- data/bin/cql +5 -1
- data/lib/activefacts.rb +3 -12
- data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
- data/lib/activefacts/version.rb +2 -2
- metadata +48 -296
- data/History.txt +0 -4
- data/LICENSE +0 -19
- data/Manifest.txt +0 -165
- data/README.rdoc +0 -81
- data/css/offline.css +0 -3
- data/css/orm2.css +0 -124
- data/css/print.css +0 -8
- data/css/style-print.css +0 -357
- data/css/style.css +0 -387
- data/download.html +0 -110
- data/examples/CQL/Address.cql +0 -44
- data/examples/CQL/Blog.cql +0 -54
- data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
- data/examples/CQL/Death.cql +0 -17
- data/examples/CQL/Diplomacy.cql +0 -48
- data/examples/CQL/Genealogy.cql +0 -98
- data/examples/CQL/Insurance.cql +0 -320
- data/examples/CQL/Marriage.cql +0 -18
- data/examples/CQL/Metamodel.cql +0 -493
- data/examples/CQL/Monogamy.cql +0 -24
- data/examples/CQL/MultiInheritance.cql +0 -22
- data/examples/CQL/NonRoleId.cql +0 -14
- data/examples/CQL/OddIdentifier.cql +0 -18
- data/examples/CQL/OilSupply.cql +0 -53
- data/examples/CQL/OneToOnes.cql +0 -17
- data/examples/CQL/Orienteering.cql +0 -111
- data/examples/CQL/PersonPlaysGame.cql +0 -18
- data/examples/CQL/RedundantDependency.cql +0 -34
- data/examples/CQL/SchoolActivities.cql +0 -33
- data/examples/CQL/SeparateSubtype.cql +0 -30
- data/examples/CQL/ServiceDirector.cql +0 -276
- data/examples/CQL/SimplestUnary.cql +0 -12
- data/examples/CQL/Supervision.cql +0 -34
- data/examples/CQL/WaiterTips.cql +0 -33
- data/examples/CQL/Warehousing.cql +0 -101
- data/examples/CQL/WindowInRoomInBldg.cql +0 -28
- data/examples/CQL/unit.cql +0 -474
- data/examples/index.html +0 -420
- data/examples/intro.html +0 -327
- data/examples/local.css +0 -24
- data/index.html +0 -111
- data/lib/activefacts/cql.rb +0 -35
- data/lib/activefacts/cql/CQLParser.treetop +0 -158
- data/lib/activefacts/cql/Context.treetop +0 -48
- data/lib/activefacts/cql/Expressions.treetop +0 -67
- data/lib/activefacts/cql/FactTypes.treetop +0 -358
- data/lib/activefacts/cql/Language/English.treetop +0 -315
- data/lib/activefacts/cql/LexicalRules.treetop +0 -253
- data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
- data/lib/activefacts/cql/Rakefile +0 -14
- data/lib/activefacts/cql/Terms.treetop +0 -183
- data/lib/activefacts/cql/ValueTypes.treetop +0 -202
- data/lib/activefacts/cql/compiler.rb +0 -156
- data/lib/activefacts/cql/compiler/clause.rb +0 -1137
- data/lib/activefacts/cql/compiler/constraint.rb +0 -581
- data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
- data/lib/activefacts/cql/compiler/expression.rb +0 -443
- data/lib/activefacts/cql/compiler/fact.rb +0 -390
- data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
- data/lib/activefacts/cql/compiler/query.rb +0 -106
- data/lib/activefacts/cql/compiler/shared.rb +0 -161
- data/lib/activefacts/cql/compiler/value_type.rb +0 -174
- data/lib/activefacts/cql/nodes.rb +0 -49
- data/lib/activefacts/cql/parser.rb +0 -241
- data/lib/activefacts/dependency_analyser.rb +0 -182
- data/lib/activefacts/generate/absorption.rb +0 -70
- data/lib/activefacts/generate/composition.rb +0 -118
- data/lib/activefacts/generate/cql.rb +0 -714
- data/lib/activefacts/generate/dm.rb +0 -279
- data/lib/activefacts/generate/help.rb +0 -64
- data/lib/activefacts/generate/helpers/inject.rb +0 -16
- data/lib/activefacts/generate/helpers/oo.rb +0 -162
- data/lib/activefacts/generate/helpers/ordered.rb +0 -605
- data/lib/activefacts/generate/helpers/rails.rb +0 -57
- data/lib/activefacts/generate/html/glossary.rb +0 -461
- data/lib/activefacts/generate/json.rb +0 -337
- data/lib/activefacts/generate/null.rb +0 -32
- data/lib/activefacts/generate/rails/models.rb +0 -246
- data/lib/activefacts/generate/rails/schema.rb +0 -216
- data/lib/activefacts/generate/records.rb +0 -46
- data/lib/activefacts/generate/ruby.rb +0 -133
- data/lib/activefacts/generate/sql/mysql.rb +0 -280
- data/lib/activefacts/generate/sql/server.rb +0 -273
- data/lib/activefacts/generate/stats.rb +0 -69
- data/lib/activefacts/generate/text.rb +0 -27
- data/lib/activefacts/generate/topics.rb +0 -265
- data/lib/activefacts/generate/traits/datavault.rb +0 -241
- data/lib/activefacts/generate/traits/oo.rb +0 -73
- data/lib/activefacts/generate/traits/ordered.rb +0 -33
- data/lib/activefacts/generate/traits/ruby.rb +0 -210
- data/lib/activefacts/generate/transform/datavault.rb +0 -266
- data/lib/activefacts/generate/transform/surrogate.rb +0 -214
- data/lib/activefacts/generate/version.rb +0 -26
- data/lib/activefacts/input/cql.rb +0 -43
- data/lib/activefacts/input/orm.rb +0 -1636
- data/lib/activefacts/mapping/rails.rb +0 -132
- data/lib/activefacts/persistence.rb +0 -15
- data/lib/activefacts/persistence/columns.rb +0 -446
- data/lib/activefacts/persistence/foreignkey.rb +0 -187
- data/lib/activefacts/persistence/index.rb +0 -240
- data/lib/activefacts/persistence/object_type.rb +0 -198
- data/lib/activefacts/persistence/reference.rb +0 -434
- data/lib/activefacts/persistence/tables.rb +0 -380
- data/lib/activefacts/registry.rb +0 -11
- data/lib/activefacts/support.rb +0 -132
- data/lib/activefacts/vocabulary.rb +0 -9
- data/lib/activefacts/vocabulary/extensions.rb +0 -1348
- data/lib/activefacts/vocabulary/metamodel.rb +0 -570
- data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
- data/script/txt2html +0 -71
- data/spec/absorption_spec.rb +0 -95
- data/spec/cql/comparison_spec.rb +0 -89
- data/spec/cql/context_spec.rb +0 -94
- data/spec/cql/contractions_spec.rb +0 -224
- data/spec/cql/deontic_spec.rb +0 -88
- data/spec/cql/entity_type_spec.rb +0 -320
- data/spec/cql/expressions_spec.rb +0 -66
- data/spec/cql/fact_type_matching_spec.rb +0 -338
- data/spec/cql/french_spec.rb +0 -21
- data/spec/cql/parser/bad_literals_spec.rb +0 -86
- data/spec/cql/parser/constraints_spec.rb +0 -19
- data/spec/cql/parser/entity_types_spec.rb +0 -106
- data/spec/cql/parser/expressions_spec.rb +0 -199
- data/spec/cql/parser/fact_types_spec.rb +0 -44
- data/spec/cql/parser/literals_spec.rb +0 -312
- data/spec/cql/parser/pragmas_spec.rb +0 -89
- data/spec/cql/parser/value_types_spec.rb +0 -42
- data/spec/cql/role_matching_spec.rb +0 -148
- data/spec/cql/samples_spec.rb +0 -244
- data/spec/cql_cql_spec.rb +0 -73
- data/spec/cql_dm_spec.rb +0 -136
- data/spec/cql_mysql_spec.rb +0 -69
- data/spec/cql_parse_spec.rb +0 -34
- data/spec/cql_ruby_spec.rb +0 -73
- data/spec/cql_sql_spec.rb +0 -72
- data/spec/cql_symbol_tables_spec.rb +0 -261
- data/spec/cqldump_spec.rb +0 -170
- data/spec/helpers/array_matcher.rb +0 -23
- data/spec/helpers/ctrl_c_support.rb +0 -52
- data/spec/helpers/diff_matcher.rb +0 -39
- data/spec/helpers/file_matcher.rb +0 -34
- data/spec/helpers/parse_to_ast_matcher.rb +0 -80
- data/spec/helpers/string_matcher.rb +0 -30
- data/spec/helpers/test_parser.rb +0 -15
- data/spec/norma_cql_spec.rb +0 -66
- data/spec/norma_ruby_spec.rb +0 -62
- data/spec/norma_ruby_sql_spec.rb +0 -107
- data/spec/norma_sql_spec.rb +0 -57
- data/spec/norma_tables_spec.rb +0 -95
- data/spec/ruby_api_spec.rb +0 -23
- data/spec/spec_helper.rb +0 -35
- data/spec/transform_surrogate_spec.rb +0 -59
- data/status.html +0 -138
- data/why.html +0 -60
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts CQL Parser.
|
|
3
|
-
# A Rakefile to run Treetop when the ActiveFacts gem is installed.
|
|
4
|
-
# This isn't mandatory but makes it much faster to start the parser.
|
|
5
|
-
# Delete the generated files during parser development.
|
|
6
|
-
#
|
|
7
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
8
|
-
#
|
|
9
|
-
task :default do
|
|
10
|
-
pattern = File.dirname(__FILE__) + '**/*.treetop'
|
|
11
|
-
files = Dir[pattern]
|
|
12
|
-
# Hopefully this quoting will work where there are spaces in filenames, and even maybe on Windows?
|
|
13
|
-
exec "tt '#{files*"' '"}'"
|
|
14
|
-
end
|
|
@@ -1,183 +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
|
-
s each?
|
|
35
|
-
s (
|
|
36
|
-
term_definition_name mapping_pragmas entity_prefix
|
|
37
|
-
&{|e| input.context.object_type(e[0].value, "entity type") }
|
|
38
|
-
/
|
|
39
|
-
t1:term_definition_name mapping_pragmas written_as any? s t2:term_definition_name
|
|
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
|
-
}
|
|
46
|
-
/
|
|
47
|
-
term_definition_name s mapping_pragmas is_where
|
|
48
|
-
&{|e| input.context.object_type(e[0].value, "objectified_fact_type") }
|
|
49
|
-
)?
|
|
50
|
-
prescan_rest
|
|
51
|
-
&{|s|
|
|
52
|
-
# Wipe any terminal failures that were added:
|
|
53
|
-
@terminal_failures = []
|
|
54
|
-
@max_terminal_failure_index = start_index
|
|
55
|
-
|
|
56
|
-
# puts "========== prescan is complete on #{(s.map{|e|e.text_value}*" ").inspect} =========="
|
|
57
|
-
false
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Do a first-pass mainly lexical analysis, looking for role name definitions and adjectives,
|
|
62
|
-
# for use in detecting terms later.
|
|
63
|
-
rule prescan_rest
|
|
64
|
-
&{|s| input.context.reset_role_names }
|
|
65
|
-
(
|
|
66
|
-
context_note # Context notes have different lexical conventions
|
|
67
|
-
/ '(' as S term_definition_name s ')' s # Prepare for a Role Name
|
|
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:
|
|
72
|
-
/ global_term # If we see A B - C D, don't recognise B as a new adjective for C D.
|
|
73
|
-
/ prescan_aggregate
|
|
74
|
-
/ id
|
|
75
|
-
# / literal # REVISIT: Literals might contain "(as Foo)" and mess things up
|
|
76
|
-
/ range # Covers all numbers and strings
|
|
77
|
-
/ comparator # handle two-character operators
|
|
78
|
-
/ S # White space and comments, must precede / and *
|
|
79
|
-
/ [-+{}\[\].,:^/%*()] # All other punctuation and operators
|
|
80
|
-
)* [?;] s
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Not sure this is even needed, but it doesn't seem to hurt:
|
|
84
|
-
rule prescan_aggregate
|
|
85
|
-
aggregate_type:id s agg_of s global_term agg_in s &'('
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
rule new_derived_value
|
|
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
|
-
}
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Derived values are new terms introduced by an = sign before an expression
|
|
103
|
-
# This rule handles trailing words of a multi-word derived value
|
|
104
|
-
rule derived_value_continuation
|
|
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
|
-
}
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Used during the pre-scan, match a term with new adjective(s)
|
|
114
|
-
rule new_adjective_term
|
|
115
|
-
!global_term adj:id '-' '-'? lead_intervening s global_term # Definitely a new leading adjective for this term
|
|
116
|
-
&{|s| adj = [s[1].text_value, s[4].value].compact*" "; input.context.new_leading_adjective_term(adj, s[6].text_value) }
|
|
117
|
-
/
|
|
118
|
-
global_term s trail_intervening '-' '-'? !global_term adj:id # Definitely a new trailing adjective for this term
|
|
119
|
-
&{|s| adj = [s[2].value, s[6].text_value].compact*" "; input.context.new_trailing_adjective_term(adj, s[0].text_value) }
|
|
120
|
-
end
|
|
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
|
-
}
|
|
129
|
-
end
|
|
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
|
-
}
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
# This is the rule to use after the prescan; it only succeeds on a complete term or role reference
|
|
141
|
-
rule term
|
|
142
|
-
s head:id x &{|s| w = s[1].text_value; input.context.term_starts?(w, s[2]) }
|
|
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>
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
rule x
|
|
153
|
-
'' <SavedContext>
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
rule global_term
|
|
157
|
-
# This rule shouldn't be used outside the prescan, it will memoize the wrong things.
|
|
158
|
-
head:id x &{|s| input.context.term_starts?(s[0].text_value, s[1]) }
|
|
159
|
-
tail:(s w:id &{|s| input.context.term_continues?(s[1].text_value) } )*
|
|
160
|
-
{ def value
|
|
161
|
-
tail.elements.inject(head.value) { |t, e| "#{t} #{e.w.value}" }
|
|
162
|
-
end
|
|
163
|
-
}
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
rule non_phrase
|
|
167
|
-
# These words are illegal in (but maybe ok following) a clause where a phrase is expected:
|
|
168
|
-
and
|
|
169
|
-
/ but
|
|
170
|
-
/ if
|
|
171
|
-
/ role_list_constraint_followers
|
|
172
|
-
/ only_if
|
|
173
|
-
/ or
|
|
174
|
-
/ quantifier
|
|
175
|
-
/ returning
|
|
176
|
-
/ then
|
|
177
|
-
/ value_constraint
|
|
178
|
-
/ where
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
@@ -1,202 +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
|
-
rule implicit_value_type_name
|
|
48
|
-
id
|
|
49
|
-
{
|
|
50
|
-
def node_type; :term; end
|
|
51
|
-
}
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
rule value_type_parameters
|
|
55
|
-
'(' s tpl:type_parameter_list? ')' s
|
|
56
|
-
{ def values; tpl.empty? ? [] : tpl.values; end }
|
|
57
|
-
/ s
|
|
58
|
-
{ def values; []; end }
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
rule type_parameter_list
|
|
62
|
-
head:number s tail:( ',' s number s )*
|
|
63
|
-
{
|
|
64
|
-
def values
|
|
65
|
-
[head.value, *tail.elements.map{|i| i.number.value}]
|
|
66
|
-
end
|
|
67
|
-
}
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
rule unit_definition
|
|
71
|
-
u:(
|
|
72
|
-
s coeff:unit_coefficient? base:units? s o:unit_offset?
|
|
73
|
-
conversion
|
|
74
|
-
singular:unit_name s plural:('/' s p:unit_name s)?
|
|
75
|
-
/
|
|
76
|
-
s singular:unit_name s plural:('/' s p:unit_name s)?
|
|
77
|
-
conversion
|
|
78
|
-
coeff:unit_coefficient? base:units? s o:unit_offset?
|
|
79
|
-
)
|
|
80
|
-
q:(approximately '' / ephemera s url )? s
|
|
81
|
-
';'
|
|
82
|
-
{
|
|
83
|
-
def ast
|
|
84
|
-
singular = u.singular.text_value
|
|
85
|
-
plural = u.plural.text_value.empty? ? nil : u.plural.p.text_value
|
|
86
|
-
if u.coeff.empty?
|
|
87
|
-
raise "Unit definition requires either a coefficient or an ephemera URL" unless q.respond_to?(:ephemera)
|
|
88
|
-
numerator,denominator = 1, 1
|
|
89
|
-
else
|
|
90
|
-
numerator, denominator = *u.coeff.ast
|
|
91
|
-
end
|
|
92
|
-
offset = u.o.text_value.empty? ? 0 : u.o.value
|
|
93
|
-
bases = u.base.empty? ? [] : u.base.value
|
|
94
|
-
approximately = q.respond_to?(:approximately) || u.conversion.approximate?
|
|
95
|
-
ephemera = q.respond_to?(:ephemera) ? q.url.text_value : nil
|
|
96
|
-
Compiler::Unit.new singular, plural, numerator, denominator, offset, bases, approximately, ephemera
|
|
97
|
-
end
|
|
98
|
-
}
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
rule unit_name
|
|
102
|
-
id
|
|
103
|
-
{
|
|
104
|
-
def node_type; :unit; end
|
|
105
|
-
}
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
rule unit_coefficient
|
|
110
|
-
numerator:number denominator:(s '/' s number)? s
|
|
111
|
-
{
|
|
112
|
-
def ast
|
|
113
|
-
[ numerator.text_value,
|
|
114
|
-
(denominator.text_value.empty? ? "1" : denominator.number.text_value)
|
|
115
|
-
]
|
|
116
|
-
end
|
|
117
|
-
}
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
rule unit_offset
|
|
121
|
-
sign:[-+] s number s
|
|
122
|
-
{ def value
|
|
123
|
-
sign.text_value == '-' ? "-"+number.text_value : number.text_value
|
|
124
|
-
end
|
|
125
|
-
}
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# In a unit definition, we may use undefined base units; this is the only way to get fundamental units
|
|
129
|
-
rule units
|
|
130
|
-
!non_unit maybe_unit s tail:(!non_unit maybe_unit s)* div:('/' s maybe_unit s tail:(!non_unit maybe_unit s)*)?
|
|
131
|
-
{ def value
|
|
132
|
-
tail.elements.inject([maybe_unit.value]) { |a, e| a << e.maybe_unit.value } +
|
|
133
|
-
(div.text_value.empty? ? [] : div.tail.elements.inject([div.maybe_unit.inverse]) { |a, e| a << e.maybe_unit.inverse })
|
|
134
|
-
end
|
|
135
|
-
}
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
rule non_unit
|
|
139
|
-
restricted_to / conversion / approximately / ephemera / auto_assignment
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
rule unit
|
|
143
|
-
maybe_unit &{|s| input.context.unit?(s[0].unit_name.text_value) }
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
rule maybe_unit
|
|
147
|
-
unit_name pow:('^' '-'? [0-9])?
|
|
148
|
-
{ def value
|
|
149
|
-
[unit_name.text_value, pow.text_value.empty? ? 1 : Integer(pow.text_value[1..-1])]
|
|
150
|
-
end
|
|
151
|
-
def inverse
|
|
152
|
-
a = value
|
|
153
|
-
a[1] = -a[1]
|
|
154
|
-
a
|
|
155
|
-
end
|
|
156
|
-
}
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
rule value_constraint
|
|
160
|
-
restricted_to restricted_values c:context_note?
|
|
161
|
-
{
|
|
162
|
-
def ast
|
|
163
|
-
v = restricted_values.values
|
|
164
|
-
c[:context_note] = c.ast unless c.empty?
|
|
165
|
-
v
|
|
166
|
-
end
|
|
167
|
-
}
|
|
168
|
-
# REVISIT: "where the possible value/s of that <Term> is/are value (, ...)"
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
rule restricted_values
|
|
172
|
-
range_list s u:units?
|
|
173
|
-
{
|
|
174
|
-
def values
|
|
175
|
-
{ :ranges => range_list.ranges,
|
|
176
|
-
:units => u.empty? ? nil : u.value
|
|
177
|
-
}
|
|
178
|
-
end
|
|
179
|
-
}
|
|
180
|
-
/
|
|
181
|
-
regular_expression
|
|
182
|
-
{
|
|
183
|
-
def values
|
|
184
|
-
{ :regular_expression => contents }
|
|
185
|
-
end
|
|
186
|
-
}
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
rule range_list
|
|
190
|
-
'{' s
|
|
191
|
-
head:range s tail:( ',' s range )*
|
|
192
|
-
'}' s
|
|
193
|
-
{
|
|
194
|
-
def ranges
|
|
195
|
-
[head.value, *tail.elements.map{|e| e.range.value }]
|
|
196
|
-
end
|
|
197
|
-
}
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
end
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# Compile a CQL string into an ActiveFacts vocabulary.
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
4
|
-
#
|
|
5
|
-
require 'activefacts/vocabulary'
|
|
6
|
-
require 'activefacts/cql/parser'
|
|
7
|
-
require 'activefacts/cql/compiler/shared'
|
|
8
|
-
require 'activefacts/cql/compiler/value_type'
|
|
9
|
-
require 'activefacts/cql/compiler/entity_type'
|
|
10
|
-
require 'activefacts/cql/compiler/clause'
|
|
11
|
-
require 'activefacts/cql/compiler/fact_type'
|
|
12
|
-
require 'activefacts/cql/compiler/expression'
|
|
13
|
-
require 'activefacts/cql/compiler/fact'
|
|
14
|
-
require 'activefacts/cql/compiler/constraint'
|
|
15
|
-
require 'activefacts/cql/compiler/query'
|
|
16
|
-
|
|
17
|
-
module ActiveFacts
|
|
18
|
-
module CQL
|
|
19
|
-
class Compiler < ActiveFacts::CQL::Parser
|
|
20
|
-
LANGUAGES = {
|
|
21
|
-
'en' => 'English',
|
|
22
|
-
'fr' => 'French',
|
|
23
|
-
'cn' => 'Mandarin'
|
|
24
|
-
}
|
|
25
|
-
attr_reader :vocabulary
|
|
26
|
-
|
|
27
|
-
def initialize *a
|
|
28
|
-
@filename = a.shift || "stdio"
|
|
29
|
-
super *a
|
|
30
|
-
@constellation = ActiveFacts::API::Constellation.new(ActiveFacts::Metamodel)
|
|
31
|
-
@language = nil
|
|
32
|
-
trace :file, "Parsing '#{@filename}'"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def compile_file filename
|
|
36
|
-
old_filename = @filename
|
|
37
|
-
@filename = filename
|
|
38
|
-
File.open(filename) do |f|
|
|
39
|
-
compile(f.read)
|
|
40
|
-
end
|
|
41
|
-
@filename = old_filename
|
|
42
|
-
@vocabulary
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Load the appropriate natural language module
|
|
46
|
-
def detect_language
|
|
47
|
-
@filename =~ /.*\.(..)\.cql$/i
|
|
48
|
-
language_code = $1
|
|
49
|
-
@language = LANGUAGES[language_code] || 'English'
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def include_language
|
|
53
|
-
detect_language unless @langage
|
|
54
|
-
require 'activefacts/cql/Language/'+@language
|
|
55
|
-
language_module = ActiveFacts::CQL.const_get(@language)
|
|
56
|
-
extend language_module
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Mark any new Concepts as belonging to this topic
|
|
60
|
-
def topic_flood
|
|
61
|
-
@constellation.Concept.each do |key, concept|
|
|
62
|
-
next if concept.topic
|
|
63
|
-
trace :topic, "Colouring #{concept.describe} with #{@topic.topic_name}"
|
|
64
|
-
concept.topic = @topic
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def compile input
|
|
69
|
-
include_language
|
|
70
|
-
|
|
71
|
-
@string = input
|
|
72
|
-
|
|
73
|
-
# The syntax tree created from each parsed CQL statement gets passed to the block.
|
|
74
|
-
# parse_all returns an array of the block's non-nil return values.
|
|
75
|
-
ok = parse_all(@string, :definition) do |node|
|
|
76
|
-
trace :parse, "Parsed '#{node.text_value.gsub(/\s+/,' ').strip}'" do
|
|
77
|
-
trace :lex, (proc { node.inspect })
|
|
78
|
-
begin
|
|
79
|
-
ast = node.ast
|
|
80
|
-
next unless ast
|
|
81
|
-
trace :ast, ast.inspect
|
|
82
|
-
ast.tree = node
|
|
83
|
-
ast.constellation = @constellation
|
|
84
|
-
ast.vocabulary = @vocabulary
|
|
85
|
-
value = compile_definition ast
|
|
86
|
-
trace :definition, "Compiled to #{value.is_a?(Array) ? value.map{|v| v.verbalise}*', ' : value.verbalise}" if value
|
|
87
|
-
if value.is_a?(ActiveFacts::Metamodel::Topic)
|
|
88
|
-
topic_flood if @topic
|
|
89
|
-
@topic = value
|
|
90
|
-
elsif ast.is_a?(Compiler::Vocabulary)
|
|
91
|
-
topic_flood if @topic
|
|
92
|
-
@vocabulary = value
|
|
93
|
-
@topic = @constellation.Topic(@vocabulary.name)
|
|
94
|
-
end
|
|
95
|
-
rescue => e
|
|
96
|
-
# Augment the exception message, but preserve the backtrace
|
|
97
|
-
start_line = @string.line_of(node.interval.first)
|
|
98
|
-
end_line = @string.line_of(node.interval.last-1)
|
|
99
|
-
lines = start_line != end_line ? "s #{start_line}-#{end_line}" : " #{start_line.to_s}"
|
|
100
|
-
ne = StandardError.new("at line#{lines} #{e.message.strip}")
|
|
101
|
-
ne.set_backtrace(e.backtrace)
|
|
102
|
-
raise ne
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
topic_flood if @topic
|
|
106
|
-
end
|
|
107
|
-
raise failure_reason unless ok
|
|
108
|
-
vocabulary
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def compile_import file, aliases
|
|
112
|
-
saved_index = @index
|
|
113
|
-
saved_block = @block
|
|
114
|
-
saved_string = @string
|
|
115
|
-
saved_input_length = @input_length
|
|
116
|
-
saved_topic = @topic
|
|
117
|
-
old_filename = @filename
|
|
118
|
-
@filename = File.dirname(old_filename)+'/'+file+'.cql'
|
|
119
|
-
|
|
120
|
-
# REVISIT: Save and use another @vocabulary for this file?
|
|
121
|
-
File.open(@filename) do |f|
|
|
122
|
-
topic_flood if @topic
|
|
123
|
-
@topic = @constellation.Topic(File.basename(@filename, '.cql'))
|
|
124
|
-
trace :import, "Importing #{@filename} as #{@topic.topic_name}" do
|
|
125
|
-
ok = parse_all(f.read, nil, &@block)
|
|
126
|
-
end
|
|
127
|
-
@topic = saved_topic
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
rescue => e
|
|
131
|
-
ne = StandardError.new("In #{@filename} #{e.message.strip}")
|
|
132
|
-
ne.set_backtrace(e.backtrace)
|
|
133
|
-
raise ne
|
|
134
|
-
ensure
|
|
135
|
-
@block = saved_block
|
|
136
|
-
@index = saved_index
|
|
137
|
-
@input_length = saved_input_length
|
|
138
|
-
@string = saved_string
|
|
139
|
-
@filename = old_filename
|
|
140
|
-
nil
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def compile_definition ast
|
|
144
|
-
ast.compile
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def unit? s
|
|
148
|
-
name = @constellation.Name[s]
|
|
149
|
-
units = (!name ? [] : Array(name.unit) + Array(name.plural_named_unit)).uniq
|
|
150
|
-
trace :units, "Looking for unit #{s}, got #{units.map{|u|u.name}.inspect}"
|
|
151
|
-
units.size > 0
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|