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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,161 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
-
5
- # In a declaration, a Binding has one or more Reference's.
6
- # A Binding is for a single ObjectType, normally related to just one Role,
7
- # and the references (References) to it will normally be the object_type name
8
- # with the same adjectives (modulo loose binding),
9
- # or a role name or subscript reference.
10
- #
11
- # In some situations a Binding will have some References with the same adjectives,
12
- # and one or more References with no adjectives - this is called "loose binding".
13
- class Binding
14
- attr_reader :player # The ObjectType (object type)
15
- attr_reader :refs # an array of the References
16
- attr_reader :role_name
17
- attr_accessor :rebound_to # Loose binding may set this to another binding
18
- attr_reader :variable
19
- attr_accessor :instance # When binding fact instances, the instance goes here
20
-
21
- def initialize player, role_name = nil
22
- @player = player
23
- @role_name = role_name
24
- @refs = []
25
- end
26
-
27
- def inspect
28
- "#{@player.name}#{@role_name and @role_name.is_a?(Integer) ? " (#{@role_name})" : " (as #{@role_name})"}"
29
- end
30
-
31
- def key
32
- "#{@player.name}#{@role_name && " (as #{@role_name})"}"
33
- end
34
-
35
- def <=>(other)
36
- key <=> other.key
37
- end
38
-
39
- def variable= v
40
- @variable = v # A place for a breakpoint :)
41
- end
42
-
43
- def add_ref ref
44
- @refs << ref
45
- ref
46
- end
47
-
48
- def delete_ref ref
49
- @refs.delete ref
50
- end
51
- end
52
-
53
- class CompilationContext
54
- attr_accessor :vocabulary
55
- attr_accessor :allowed_forward_terms
56
- attr_accessor :left_contraction_allowed
57
- attr_accessor :left_contractable_clause
58
- attr_accessor :left_contraction_conjunction
59
- attr_reader :bindings # The Bindings in this declaration
60
- attr_reader :player_by_role_name
61
-
62
- def initialize vocabulary
63
- @vocabulary = vocabulary
64
- @vocabulary_identifier = @vocabulary.identifying_role_values
65
- @allowed_forward_terms = []
66
- @bindings = {}
67
- @player_by_role_name = {}
68
- @left_contraction_allowed = false
69
- end
70
-
71
- # Look up this object_type by its name
72
- def object_type(name)
73
- constellation = @vocabulary.constellation
74
- player = constellation.ObjectType[[@vocabulary_identifier, name]]
75
-
76
- # Bind to an existing role which has a role name (that's why we bind those first)
77
- player ||= @player_by_role_name[name]
78
-
79
- if !player && @allowed_forward_terms.include?(name)
80
- @vocabulary.valid_entity_type_name(name) # No need for the result here, just no exceptional condition
81
- player = constellation.EntityType(@vocabulary, name, :concept => :new)
82
- end
83
-
84
- player
85
- end
86
-
87
- # Pass in an array of clauses or References for player identification and binding (creating the Bindings)
88
- # It's necessary to identify all players that define a role name first,
89
- # so those names exist in the context for where they're used.
90
- def bind *clauses
91
- cl = clauses.flatten
92
- cl.each { |clause| clause.identify_players_with_role_name(self) }
93
- cl.each { |clause| clause.identify_other_players(self) }
94
- cl.each { |clause| clause.bind(self) }
95
- end
96
- end
97
-
98
- class Definition
99
- attr_accessor :constellation, :vocabulary, :tree
100
- def compile
101
- raise "#{self.class} should implement the compile method"
102
- end
103
-
104
- def to_s
105
- @vocabulary ? "#{vocabulary.to_s}::" : ''
106
- end
107
-
108
- def source
109
- @tree.text_value
110
- end
111
- end
112
-
113
- class Vocabulary < Definition
114
- def initialize name
115
- @name = name
116
- end
117
-
118
- def compile
119
- if @constellation.Vocabulary.size > 0
120
- @constellation.Topic @name
121
- else
122
- @constellation.Vocabulary @name
123
- end
124
- end
125
-
126
- def to_s
127
- @name
128
- end
129
- end
130
-
131
- class Import < Definition
132
- def initialize parser, name, alias_hash
133
- @parser = parser
134
- @name = name
135
- @alias_hash = alias_hash
136
- end
137
-
138
- def to_s
139
- "#{@vocabulary.to_s} imports #{@alias_hash.map{|k,v| "#{k} as #{v}" }*', '};"
140
- end
141
-
142
- def compile
143
- @parser.compile_import(@name, @alias_hash)
144
- end
145
- end
146
-
147
- class ObjectType < Definition
148
- attr_reader :name
149
-
150
- def initialize name
151
- @name = name
152
- end
153
-
154
- def to_s
155
- "#{super}#{@name}"
156
- end
157
- end
158
-
159
- end
160
- end
161
- end
@@ -1,174 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Compiler < ActiveFacts::CQL::Parser
4
-
5
- class Unit < Definition
6
- def initialize singular, plural, numerator, denominator, offset, base_units, approximately, ephemera_url
7
- @singular = singular
8
- @plural = plural
9
- @numerator, @denominator = numerator, denominator
10
- @offset = offset
11
- @base_units = base_units # An array of pairs, each [unit_name, power]
12
- @approximately = approximately
13
- @ephemera_url = ephemera_url
14
- end
15
-
16
- def compile
17
- if (@numerator.to_f / @denominator.to_i != 1.0)
18
- coefficient = @constellation.Coefficient(
19
- @numerator,
20
- @denominator.to_i,
21
- !@approximately
22
- # REVISIT: Activefacts-api is complaining at present. The following is better and should work:
23
- # :numerator => @numerator,
24
- # :denominator => @denominator.to_i,
25
- # :is_precise => !@approximately
26
- )
27
- else
28
- coefficient = nil
29
- end
30
- @offset = nil if @offset.to_f == 0
31
-
32
- trace :units, "Defining new unit #{@singular}#{@plural ? "/"+@plural : ""}" do
33
- trace :units, "Coefficient is #{coefficient.numerator}#{coefficient.denominator != 1 ? "/#{coefficient.denominator}" : ""} #{coefficient.is_precise ? "exactly" : "approximately"}" if coefficient
34
- trace :units, "Offset is #{@offset}" if @offset
35
- raise "Redefinition of unit #{@singular}" if @constellation.Unit.values.detect{|u| u.name == @singular}
36
- raise "Redefinition of unit #{@plural}" if @constellation.Unit.values.detect{|u| u.name == @plural}
37
- unit = @constellation.Unit(:new,
38
- :name => @singular,
39
- :plural_name => @plural,
40
- :coefficient => coefficient,
41
- :offset => @offset,
42
- :is_fundamental => @base_units.empty?,
43
- :ephemera_url => @ephemera_url,
44
- :vocabulary => @vocabulary
45
- )
46
- @base_units.each do |base_unit, exponent|
47
- base = @constellation.Unit.values.detect{|u| u.name == base_unit || u.plural_name == base_unit }
48
- trace :units, "Base unit #{base_unit}^#{exponent} #{base ? "" : "(implicitly fundamental)"}"
49
- base ||= @constellation.Unit(:new, :name => base_unit, :is_fundamental => true, :vocabulary => @vocabulary)
50
- @constellation.Derivation(:derived_unit => unit, :base_unit => base, :exponent => exponent)
51
- end
52
- =begin
53
- if @plural
54
- plural_unit = @constellation.Unit(:new,
55
- :name => @plural,
56
- :is_fundamental => false,
57
- :vocabulary => @vocabulary
58
- )
59
- @constellation.Derivation(:derived_unit => plural_unit, :base_unit => unit, :exponent => 1)
60
- end
61
- =end
62
- unit
63
- end
64
- end
65
-
66
- def inspect
67
- to_s
68
- end
69
-
70
- def to_s
71
- super + "Unit(#{
72
- @singular
73
- }#{
74
- @plural ? '/'+@plural : ''
75
- }) is #{
76
- @numerator
77
- }/#{
78
- @denominator
79
- }+#{
80
- @offset
81
- } #{
82
- @base_units.map{|b,e|
83
- b+'^'+e.to_s
84
- }*'*'
85
- }"
86
- end
87
- end
88
-
89
- class ValueType < ObjectType
90
- def initialize name, base, parameters, unit, value_constraint, pragmas, context_note, auto_assigned_at
91
- super name
92
- @base_type_name = base
93
- @parameters = parameters
94
- @unit = unit
95
- @value_constraint = value_constraint
96
- @pragmas = pragmas
97
- @context_note = context_note
98
- @auto_assigned_at = auto_assigned_at
99
- end
100
-
101
- def compile
102
- length, scale = *@parameters
103
-
104
- # Create the base type unless it already exists:
105
- base_type = nil
106
- if (@base_type_name != @name)
107
- unless base_type = @vocabulary.valid_value_type_name(@base_type_name)
108
- base_type = @constellation.ValueType(@vocabulary, @base_type_name, :concept => :new)
109
- return base_type if @base_type_name == @name
110
- end
111
- end
112
-
113
- # Create and initialise the ValueType:
114
- vt = @vocabulary.valid_value_type_name(@name) ||
115
- @constellation.ValueType(@vocabulary, @name, :concept => :new)
116
- vt.is_independent = true if @pragmas.delete('independent')
117
- @pragmas.each do |p|
118
- @constellation.ConceptAnnotation(:concept => vt.concept, :mapping_annotation => p)
119
- end if @pragmas
120
- vt.supertype = base_type if base_type
121
- vt.length = length if length
122
- vt.scale = scale if scale
123
- vt.transaction_phase = @auto_assigned_at
124
-
125
- unless @unit.empty?
126
- unit_name, exponent = *@unit[0]
127
- unit = @constellation.Name[unit_name].unit ||
128
- @constellation.Name[unit_name].plural_named_unit
129
- raise "Unit #{unit_name} for value type #{@name} is not defined" unless unit
130
- if exponent != 1
131
- base_unit = unit
132
- unit_name = base_unit.name+"^#{exponent}"
133
- unless unit = @constellation.Unit.detect{|k,v| v.name == unit_name }
134
- # Define a derived unit (these are skipped on output)
135
- unit = @constellation.Unit(:new,
136
- :vocabulary => @vocabulary,
137
- :name => unit_name,
138
- :is_fundamental => false
139
- )
140
- @constellation.Derivation(unit, base_unit).exponent = exponent
141
- end
142
- end
143
- vt.unit = unit
144
- end
145
-
146
- if @value_constraint
147
- @value_constraint.constellation = @constellation
148
- vt.value_constraint = @value_constraint.compile
149
- end
150
-
151
- if @context_note
152
- @context_note.compile(@constellation, vt)
153
- end
154
-
155
- vt
156
- end
157
-
158
- def to_s
159
- "ValueType: #{super} is written as #{
160
- @base_type_name
161
- }#{
162
- @parameters.size > 0 ? "(#{ @parameters.map{|p|p.to_s}*', ' })" : ''
163
- }#{
164
- @unit && @unit.length > 0 ? " in #{@unit.inspect}" : ''
165
- }#{
166
- @value_constraint ? " "+@value_constraint.to_s : ''
167
- }#{
168
- @pragmas.size > 0 ? ", pragmas [#{@pragmas*','}]" : ''
169
- };"
170
- end
171
- end
172
- end
173
- end
174
- end
@@ -1,49 +0,0 @@
1
- module ActiveFacts
2
- module CQL
3
- class Parser
4
- class TermNode < Treetop::Runtime::SyntaxNode
5
- def ast quantifier = nil, function_call = nil, role_name = nil, value_constraint = nil, literal = nil, nested_clauses = nil
6
- t = x.context[:term]
7
- gt = x.context[:global_term]
8
- if t.size > gt.size and t[-gt.size..-1] == gt
9
- leading_adjective = t[0...-gt.size-1]
10
- leading_adjective.sub!(/ /, '-') if !tail.elements[0].dbl.empty?
11
- end
12
- if t.size > gt.size and t[0...gt.size] == gt
13
- trailing_adjective = t[gt.size+1..-1]
14
- trailing_adjective.sub!(/ (\S*)\Z/, '-\1') if !tail.elements[-1].dbl.empty?
15
- end
16
- Compiler::Reference.new(gt, leading_adjective, trailing_adjective, quantifier, function_call, role_name, value_constraint, literal, nested_clauses)
17
- end
18
-
19
- def value # Sometimes we just want the full term name
20
- x.context[:term]
21
- end
22
-
23
- def node_type
24
- :term
25
- end
26
- end
27
-
28
- class TermLANode < TermNode
29
- def ast quantifier = nil, function_call = nil, role_name = nil, value_constraint = nil, literal = nil, nested_clauses = nil
30
- ast = term.ast(quantifier, function_call, role_name, value_constraint, literal, nested_clauses)
31
- ast.leading_adjective = head.text_value
32
- ast
33
- end
34
- end
35
-
36
- class TermDefinitionNameNode < TermNode
37
- def value
38
- t.elements.inject([
39
- id.value
40
- ]){|a, e| a << e.id.value}*' '
41
- end
42
-
43
- def node_type
44
- :term
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,241 +0,0 @@
1
- #
2
- # ActiveFacts CQL Parser.
3
- # The parser turns CQL strings into abstract syntax trees ready for semantic analysis.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'rubygems'
8
- require 'treetop'
9
-
10
- # These are Treetop files, which Polyglot will compile on the fly if precompiled ones aren't found:
11
- require 'activefacts/cql/LexicalRules'
12
- require 'activefacts/cql/Language/English'
13
- require 'activefacts/cql/Expressions'
14
- require 'activefacts/cql/Terms'
15
- require 'activefacts/cql/ObjectTypes'
16
- require 'activefacts/cql/ValueTypes'
17
- require 'activefacts/cql/FactTypes'
18
- require 'activefacts/cql/Context'
19
- require 'activefacts/cql/CQLParser'
20
-
21
- module ActiveFacts
22
- module CQL
23
- class Parser < CQLParser
24
- end
25
- end
26
- end
27
- require 'activefacts/cql/nodes'
28
-
29
- class Treetop::Runtime::SyntaxNode
30
- def node_type
31
- terminal? ? :keyword : :composite
32
- end
33
- end
34
-
35
- module ActiveFacts
36
- module CQL
37
- module Terms
38
- class SavedContext < Treetop::Runtime::SyntaxNode
39
- attr_accessor :context
40
- end
41
- end
42
-
43
- # Extend the generated parser:
44
- class Parser
45
- include ActiveFacts
46
-
47
- # The Context manages some key information revealed or needed during parsing
48
- # These methods are semantic predicates; if they return false this parse rule will fail.
49
- class Context
50
- attr_reader :term, :global_term
51
- attr_reader :terms
52
-
53
- def initialize(parser)
54
- @parser = parser
55
- @terms = {}
56
- @role_names = {}
57
- @allowed_forward_terms = []
58
- end
59
-
60
- def object_type(name, kind)
61
- index_name(@terms, name) && trace(:context, "new #{kind} '#{name}'")
62
- true
63
- end
64
-
65
- def reset_role_names
66
- trace :context, "\tresetting role names #{@role_names.keys.sort*", "}" if @role_names && @role_names.size > 0
67
- @role_names = {}
68
- end
69
-
70
- def allowed_forward_terms(terms)
71
- @allowed_forward_terms = terms
72
- end
73
-
74
- def new_leading_adjective_term(adj, term)
75
- index_name(@role_names, "#{adj} #{term}", term) && trace(:context, "new compound term '#{adj}- #{term}'")
76
- true
77
- end
78
-
79
- def new_trailing_adjective_term(adj, term)
80
- index_name(@role_names, "#{term} #{adj}", term) && trace(:context, "new compound term '#{term} -#{adj}'")
81
- true
82
- end
83
-
84
- def role_name(name)
85
- index_name(@role_names, name) && trace(:context, "new role '#{name}'")
86
- true
87
- end
88
-
89
- def term_starts?(s, context_saver)
90
- @term = @global_term = nil
91
-
92
- @term_part = s
93
- @context_saver = context_saver
94
- t = @terms[s] || @role_names[s] || system_term(s)
95
- if t
96
- # s is a prefix of the keys of t.
97
- if t[s]
98
- @global_term = @term = @term_part
99
- @context_saver.context = {:term => @term, :global_term => @global_term }
100
- end
101
- trace :context, "Term #{t[s] ? "is" : "starts"} '#{@term_part}'"
102
- elsif @allowed_forward_terms.include?(@term_part)
103
- @term = @term_part
104
- @context_saver.context = {:term => @term, :global_term => @term }
105
- trace :context, "Term #{s} is an allowed forward"
106
- return true
107
- end
108
- t
109
- end
110
-
111
- def term_continues?(s)
112
- @term_part = "#{@term_part} #{s}"
113
- t = @terms[@term_part]
114
- r = @role_names[@term_part]
115
- if t && (!r || !r[@term_part]) # Part of a term and not a complete role name
116
- w = "term"
117
- else
118
- t = r
119
- w = "role_name"
120
- end
121
- if t
122
- trace :context, "Multi-word #{w} #{t[@term_part] ? 'ends at' : 'continues to'} #{@term_part.inspect}"
123
-
124
- # Record the name of the full term and the underlying global term:
125
- if t[@term_part]
126
- @term = @term_part if t[@term_part]
127
- @global_term = (t = t[@term_part]) == true ? @term_part : t
128
- trace :context, "saving context #{@term}/#{@global_term}"
129
- @context_saver.context = {:term => @term, :global_term => @global_term }
130
- end
131
- end
132
- t
133
- end
134
-
135
- def term_complete?
136
- return true if @allowed_forward_terms.include?(@term)
137
- return true if system_term(@term)
138
- (t = @terms[@term] and t[@term]) or
139
- (t = @role_names[@term] and t[@term])
140
- end
141
-
142
- def system_term(s)
143
- false
144
- end
145
-
146
- def unit? s
147
- @parser.unit? s
148
- end
149
-
150
- private
151
- # Index the name by all prefixes
152
- def index_name(index, name, value = true)
153
- added = false
154
- words = name.split(/\s+/)
155
- words.inject("") do |n, w|
156
- # Index all prefixes up to the full term
157
- n = n.empty? ? w : "#{n} #{w}"
158
- index[n] ||= {}
159
- added = true unless index[n][name]
160
- index[n][name] = value # Save all possible completions of this prefix
161
- n
162
- end
163
- added
164
- end
165
- end
166
-
167
- class InputProxy
168
- attr_reader :context, :parser
169
-
170
- def initialize(input, context, parser)
171
- @input = input
172
- @context = context
173
- @parser = parser
174
- end
175
-
176
- def length
177
- @input.length
178
- end
179
-
180
- def size
181
- length
182
- end
183
-
184
- def [](*a)
185
- @input[*a]
186
- end
187
-
188
- def index(*a)
189
- @input.index(*a)
190
- end
191
-
192
- def line_of(x)
193
- @input.line_of(x)
194
- end
195
-
196
- def column_of(x)
197
- @input.column_of(x)
198
- end
199
- end
200
-
201
- def context
202
- @context ||= Context.new(self)
203
- end
204
-
205
- def unit?(s)
206
- # puts "Asking whether #{s.inspect} is a unit"
207
- true
208
- end
209
-
210
- def parse(input, options = {})
211
- input = InputProxy.new(input, context, self) unless input.respond_to?(:context)
212
- super(input, options)
213
- end
214
-
215
- def parse_all(input, rule_name = nil, &block)
216
- self.root = rule_name if rule_name
217
-
218
- @index = 0 # Byte offset to start next parse
219
- @block = block
220
- self.consume_all_input = false
221
- nodes = []
222
- begin
223
- node = parse(InputProxy.new(input, context, self), :index => @index)
224
- unless node
225
- raise failure_reason unless @index == input.size
226
- return nil # No input, or no more input
227
- end
228
- if @block
229
- @block.call(node)
230
- else
231
- nodes << node
232
- end
233
- end until self.index == @input_length
234
- @block ? true : nodes
235
- end
236
- end
237
-
238
- end
239
-
240
- Polyglot.register('cql', CQL::Parser)
241
- end