activefacts 0.8.6 → 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +33 -2
- data/README.rdoc +30 -36
- data/Rakefile +16 -20
- data/bin/afgen +17 -11
- data/bin/cql +313 -36
- data/download.html +43 -19
- data/examples/CQL/Address.cql +15 -15
- data/examples/CQL/Blog.cql +8 -8
- data/examples/CQL/CompanyDirectorEmployee.cql +6 -5
- data/examples/CQL/Death.cql +3 -3
- data/examples/CQL/Diplomacy.cql +48 -0
- data/examples/CQL/Genealogy.cql +41 -41
- data/examples/CQL/Insurance.cql +311 -0
- data/examples/CQL/JoinEquality.cql +35 -0
- data/examples/CQL/Marriage.cql +1 -1
- data/examples/CQL/Metamodel.cql +290 -185
- data/examples/CQL/MetamodelNext.cql +420 -0
- data/examples/CQL/Monogamy.cql +24 -0
- data/examples/CQL/MonthInSeason.cql +27 -0
- data/examples/CQL/Moon.cql +23 -0
- data/examples/CQL/MultiInheritance.cql +4 -4
- data/examples/CQL/NonRoleId.cql +14 -0
- data/examples/CQL/OddIdentifier.cql +18 -0
- data/examples/CQL/OilSupply.cql +24 -24
- data/examples/CQL/OneToOnes.cql +17 -0
- data/examples/CQL/Orienteering.cql +55 -55
- data/examples/CQL/OrienteeringER.cql +58 -0
- data/examples/CQL/PersonPlaysGame.cql +2 -2
- data/examples/CQL/RedundantDependency.cql +34 -0
- data/examples/CQL/SchoolActivities.cql +5 -5
- data/examples/CQL/SeparateSubtype.cql +28 -0
- data/examples/CQL/ServiceDirector.cql +283 -0
- data/examples/CQL/SimplestUnary.cql +2 -2
- data/examples/CQL/SubtypePI.cql +11 -11
- data/examples/CQL/Supervision.cql +38 -0
- data/examples/CQL/Tests.Test5.Load.cql +38 -0
- data/examples/CQL/WaiterTips.cql +33 -0
- data/examples/CQL/Warehousing.cql +55 -53
- data/examples/CQL/WindowInRoomInBldg.cql +9 -9
- data/examples/CQL/unit.cql +433 -544
- data/examples/index.html +314 -170
- data/examples/intro.html +6 -176
- data/examples/local.css +8 -4
- data/index.html +40 -25
- data/lib/activefacts/api/concept.rb +2 -2
- data/lib/activefacts/api/constellation.rb +4 -4
- data/lib/activefacts/api/instance.rb +2 -2
- data/lib/activefacts/api/instance_index.rb +4 -0
- data/lib/activefacts/api/numeric.rb +3 -1
- data/lib/activefacts/api/role.rb +1 -1
- data/lib/activefacts/api/standard_types.rb +23 -16
- data/lib/activefacts/api/support.rb +3 -1
- data/lib/activefacts/api/vocabulary.rb +4 -0
- data/lib/activefacts/cql/CQLParser.treetop +87 -39
- data/lib/activefacts/cql/Concepts.treetop +95 -69
- data/lib/activefacts/cql/Context.treetop +11 -2
- data/lib/activefacts/cql/Expressions.treetop +23 -59
- data/lib/activefacts/cql/FactTypes.treetop +141 -95
- data/lib/activefacts/cql/Language/English.treetop +33 -21
- data/lib/activefacts/cql/LexicalRules.treetop +6 -1
- data/lib/activefacts/cql/Terms.treetop +75 -26
- data/lib/activefacts/cql/ValueTypes.treetop +52 -54
- data/lib/activefacts/cql/compiler.rb +46 -1691
- data/lib/activefacts/cql/compiler/constraint.rb +602 -0
- data/lib/activefacts/cql/compiler/entity_type.rb +425 -0
- data/lib/activefacts/cql/compiler/fact.rb +300 -0
- data/lib/activefacts/cql/compiler/fact_type.rb +230 -0
- data/lib/activefacts/cql/compiler/reading.rb +832 -0
- data/lib/activefacts/cql/compiler/shared.rb +109 -0
- data/lib/activefacts/cql/compiler/value_type.rb +104 -0
- data/lib/activefacts/cql/parser.rb +132 -81
- data/lib/activefacts/generate/cql.rb +397 -274
- data/lib/activefacts/generate/oo.rb +13 -12
- data/lib/activefacts/generate/ordered.rb +107 -117
- data/lib/activefacts/generate/ruby.rb +34 -38
- data/lib/activefacts/generate/sql/mysql.rb +62 -45
- data/lib/activefacts/generate/sql/server.rb +59 -42
- data/lib/activefacts/input/cql.rb +6 -3
- data/lib/activefacts/input/orm.rb +991 -557
- data/lib/activefacts/persistence/columns.rb +16 -12
- data/lib/activefacts/persistence/foreignkey.rb +7 -4
- data/lib/activefacts/persistence/index.rb +3 -4
- data/lib/activefacts/persistence/reference.rb +5 -2
- data/lib/activefacts/support.rb +20 -14
- data/lib/activefacts/version.rb +1 -1
- data/lib/activefacts/vocabulary.rb +1 -0
- data/lib/activefacts/vocabulary/extensions.rb +328 -44
- data/lib/activefacts/vocabulary/metamodel.rb +145 -20
- data/lib/activefacts/vocabulary/verbaliser.rb +621 -0
- data/spec/absorption_spec.rb +4 -4
- data/spec/api/value_type.rb +1 -1
- data/spec/cql/context_spec.rb +45 -22
- data/spec/cql/deontic_spec.rb +88 -0
- data/spec/cql/matching_spec.rb +517 -0
- data/spec/cql/samples_spec.rb +88 -31
- data/spec/cql/unit_spec.rb +58 -37
- data/spec/cql_cql_spec.rb +12 -7
- data/spec/cql_mysql_spec.rb +3 -7
- data/spec/cql_parse_spec.rb +0 -4
- data/spec/cql_ruby_spec.rb +1 -4
- data/spec/cql_sql_spec.rb +5 -18
- data/spec/cql_symbol_tables_spec.rb +3 -0
- data/spec/cqldump_spec.rb +0 -2
- data/spec/helpers/array_matcher.rb +35 -0
- data/spec/helpers/ctrl_c_support.rb +52 -0
- data/spec/helpers/diff_matcher.rb +38 -0
- data/spec/helpers/file_matcher.rb +5 -3
- data/spec/helpers/string_matcher.rb +39 -0
- data/spec/helpers/test_parser.rb +13 -0
- data/spec/norma_cql_spec.rb +13 -5
- data/spec/norma_ruby_spec.rb +11 -3
- data/spec/{absorption_ruby_spec.rb → norma_ruby_sql_spec.rb} +37 -32
- data/spec/norma_sql_spec.rb +11 -5
- data/spec/norma_tables_spec.rb +33 -29
- data/spec/spec_helper.rb +4 -1
- data/status.html +92 -23
- metadata +102 -36
- data/lib/activefacts/generate/cql/html.rb +0 -403
@@ -0,0 +1,109 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module CQL
|
3
|
+
class Compiler < ActiveFacts::CQL::Parser
|
4
|
+
|
5
|
+
# In a declaration, a Binding has one or more RoleRef's.
|
6
|
+
# A Binding is for a single Concept, normally related to just one Role,
|
7
|
+
# and the references (RoleRefs) to it will normally be the concept 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 RoleRefs with the same adjectives,
|
12
|
+
# and one or more RoleRefs with no adjectives - this is called "loose binding".
|
13
|
+
class Binding
|
14
|
+
attr_reader :player # The Concept (object type)
|
15
|
+
attr_reader :refs # an array of the RoleRefs
|
16
|
+
attr_reader :role_name
|
17
|
+
attr_accessor :rebound_to # Loose binding may set this to another binding
|
18
|
+
attr_accessor :join_node
|
19
|
+
|
20
|
+
def initialize player, role_name = nil
|
21
|
+
@player = player
|
22
|
+
@role_name = role_name
|
23
|
+
@refs = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"#{@player.name}#{@role_name and @role_name.is_a?(Integer) ? " (#{@role_name})" : " (as #{@role_name})"}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def key
|
31
|
+
"#{@player.name}#{@role_name && " (as #{@role_name})"}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def <=>(other)
|
35
|
+
key <=> other.key
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class CompilationContext
|
40
|
+
attr_accessor :allowed_forward_terms
|
41
|
+
attr_reader :bindings # The Bindings in this declaration
|
42
|
+
attr_reader :player_by_role_name
|
43
|
+
|
44
|
+
def initialize vocabulary
|
45
|
+
@vocabulary = vocabulary
|
46
|
+
@vocabulary_identifier = @vocabulary.identifying_role_values
|
47
|
+
@allowed_forward_terms = []
|
48
|
+
@bindings = {}
|
49
|
+
@player_by_role_name = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Look up this concept by its name
|
53
|
+
def concept(name)
|
54
|
+
constellation = @vocabulary.constellation
|
55
|
+
player = constellation.Concept[[@vocabulary_identifier, name]]
|
56
|
+
|
57
|
+
# Bind to an existing role which has a role name (that's why we bind those first)
|
58
|
+
player ||= @player_by_role_name[name]
|
59
|
+
|
60
|
+
if !player && @allowed_forward_terms.include?(name)
|
61
|
+
player = constellation.EntityType(@vocabulary, name)
|
62
|
+
end
|
63
|
+
|
64
|
+
player
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Definition
|
69
|
+
attr_accessor :constellation, :vocabulary, :source
|
70
|
+
def compile
|
71
|
+
raise "#{self.class} should implement the compile method"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Vocabulary < Definition
|
76
|
+
def initialize name
|
77
|
+
@name = name
|
78
|
+
end
|
79
|
+
|
80
|
+
def compile
|
81
|
+
@constellation.Vocabulary @name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Import < Definition
|
86
|
+
def initialize name, alias_list
|
87
|
+
@name = name
|
88
|
+
@alias_list = alias_list
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Concept < Definition
|
93
|
+
attr_reader :name
|
94
|
+
|
95
|
+
def initialize name
|
96
|
+
@name = name
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
require 'activefacts/cql/compiler/value_type'
|
105
|
+
require 'activefacts/cql/compiler/entity_type'
|
106
|
+
require 'activefacts/cql/compiler/reading'
|
107
|
+
require 'activefacts/cql/compiler/fact_type'
|
108
|
+
require 'activefacts/cql/compiler/fact'
|
109
|
+
require 'activefacts/cql/compiler/constraint'
|
@@ -0,0 +1,104 @@
|
|
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 => @numerator,
|
20
|
+
:denominator => @denominator.to_i,
|
21
|
+
:is_precise => !@approximately
|
22
|
+
)
|
23
|
+
else
|
24
|
+
coefficient = nil
|
25
|
+
end
|
26
|
+
@offset = nil if @offset.to_f == 0
|
27
|
+
|
28
|
+
debug :units, "Defining new unit #{@singular}#{@plural ? "/"+@plural : ""}" do
|
29
|
+
debug :units, "Coefficient is #{coefficient.numerator}#{coefficient.denominator != 1 ? "/#{coefficient.denominator}" : ""} #{coefficient.is_precise ? "exactly" : "approximately"}" if coefficient
|
30
|
+
debug :units, "Offset is #{@offset}" if @offset
|
31
|
+
raise "Redefinition of unit #{@singular}" if @constellation.Unit.values.detect{|u| u.name == @singular}
|
32
|
+
raise "Redefinition of unit #{@plural}" if @constellation.Unit.values.detect{|u| u.name == @plural}
|
33
|
+
unit = @constellation.Unit(:new,
|
34
|
+
:name => @singular,
|
35
|
+
:plural_name => @plural,
|
36
|
+
:coefficient => coefficient,
|
37
|
+
:offset => @offset,
|
38
|
+
:is_fundamental => @base_units.empty?,
|
39
|
+
:ephemera_url => @ephemera_url,
|
40
|
+
:vocabulary => @vocabulary
|
41
|
+
)
|
42
|
+
@base_units.each do |base_unit, exponent|
|
43
|
+
base = @constellation.Unit.values.detect{|u| u.name == base_unit || u.plural_name == base_unit }
|
44
|
+
debug :units, "Base unit #{base_unit}^#{exponent} #{base ? "" : "(implicitly fundamental)"}"
|
45
|
+
base ||= @constellation.Unit(:new, :name => base_unit, :is_fundamental => true, :vocabulary => @vocabulary)
|
46
|
+
@constellation.Derivation(:derived_unit => unit, :base_unit => base, :exponent => exponent)
|
47
|
+
end
|
48
|
+
=begin
|
49
|
+
if @plural
|
50
|
+
plural_unit = @constellation.Unit(:new,
|
51
|
+
:name => @plural,
|
52
|
+
:is_fundamental => false,
|
53
|
+
:vocabulary => @vocabulary
|
54
|
+
)
|
55
|
+
@constellation.Derivation(:derived_unit => plural_unit, :base_unit => unit, :exponent => 1)
|
56
|
+
end
|
57
|
+
=end
|
58
|
+
unit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class ValueType < Concept
|
64
|
+
def initialize name, base, parameters, unit, value_constraint, pragmas
|
65
|
+
super name
|
66
|
+
@base_type_name = base
|
67
|
+
@parameters = parameters
|
68
|
+
@unit = unit
|
69
|
+
@value_constraint = value_constraint
|
70
|
+
@pragmas = pragmas
|
71
|
+
end
|
72
|
+
|
73
|
+
def compile
|
74
|
+
length, scale = *@parameters
|
75
|
+
|
76
|
+
# Create the base type:
|
77
|
+
base_type = nil
|
78
|
+
if (@base_type_name != @name)
|
79
|
+
unless base_type = @constellation.ValueType[[@vocabulary.identifying_role_values, @constellation.Name(@base_type_name)]]
|
80
|
+
base_type = @constellation.ValueType(@vocabulary, @base_type_name)
|
81
|
+
return base_type if @base_type_name == @name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Create and initialise the ValueType:
|
86
|
+
vt = @constellation.ValueType(@vocabulary, @name)
|
87
|
+
vt.is_independent = true if (@pragmas.include? 'independent')
|
88
|
+
vt.supertype = base_type if base_type
|
89
|
+
vt.length = length if length
|
90
|
+
vt.scale = scale if scale
|
91
|
+
|
92
|
+
raise "REVISIT: ValueType units are recognised but not yet compiled" unless @unit.empty?
|
93
|
+
|
94
|
+
if @value_constraint
|
95
|
+
@value_constraint.constellation = @constellation
|
96
|
+
vt.value_constraint = @value_constraint.compile
|
97
|
+
end
|
98
|
+
|
99
|
+
vt
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -7,7 +7,7 @@
|
|
7
7
|
require 'rubygems'
|
8
8
|
require 'treetop'
|
9
9
|
|
10
|
-
# These are Treetop files, which
|
10
|
+
# These are Treetop files, which Polyglot will compile on the fly if precompiled ones aren't found:
|
11
11
|
require 'activefacts/cql/LexicalRules'
|
12
12
|
require 'activefacts/cql/Language/English'
|
13
13
|
require 'activefacts/cql/Expressions'
|
@@ -20,17 +20,136 @@ require 'activefacts/cql/CQLParser'
|
|
20
20
|
|
21
21
|
module ActiveFacts
|
22
22
|
module CQL
|
23
|
+
module Terms
|
24
|
+
class SavedContext < Treetop::Runtime::SyntaxNode
|
25
|
+
attr_accessor :context
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
23
29
|
# Extend the generated parser:
|
24
30
|
class Parser < CQLParser
|
25
31
|
include ActiveFacts
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
# The Context manages some key information revealed or needed during parsing
|
34
|
+
# These methods are semantic predicates; if they return false this parse rule will fail.
|
35
|
+
class Context
|
36
|
+
attr_reader :term, :global_term
|
37
|
+
|
38
|
+
def initialize(parser)
|
39
|
+
@parser = parser
|
40
|
+
@terms = {}
|
41
|
+
@role_names = {}
|
42
|
+
@allowed_forward_terms = []
|
43
|
+
end
|
44
|
+
|
45
|
+
def object_type(name, kind)
|
46
|
+
index_name(@terms, name) && debug(:context, "new #{kind} '#{name}'")
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_role_names
|
51
|
+
debug :context, "\tresetting role names #{@role_names.keys.sort*", "}" if @role_names && @role_names.size > 0
|
52
|
+
@role_names = {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def allowed_forward_terms(terms)
|
56
|
+
@allowed_forward_terms = terms
|
57
|
+
end
|
58
|
+
|
59
|
+
def new_leading_adjective_term(adj, term)
|
60
|
+
index_name(@role_names, "#{adj} #{term}", term) && debug(:context, "new role '#{adj}- #{term}'")
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
def new_trailing_adjective_term(adj, term)
|
65
|
+
index_name(@role_names, n = "#{term} #{adj}", term) && debug(:context, "new role '#{term} -#{adj}'")
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def role_name(name)
|
70
|
+
index_name(@role_names, name) && debug(:context, "new role '#{name}'")
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def term_starts?(s, context_saver)
|
75
|
+
@term = @global_term = nil
|
76
|
+
|
77
|
+
@term_part = s
|
78
|
+
@context_saver = context_saver
|
79
|
+
t = @terms[s] || @role_names[s] || system_term(s)
|
80
|
+
if t
|
81
|
+
# s is a prefix of the keys of t.
|
82
|
+
if t[s]
|
83
|
+
@global_term = @term = @term_part
|
84
|
+
@context_saver.context = {:term => @term, :global_term => @global_term }
|
85
|
+
end
|
86
|
+
debug :context, "Term #{t[s] ? "is" : "starts"} '#{@term_part}'"
|
87
|
+
elsif @allowed_forward_terms.include?(@term_part)
|
88
|
+
@term = @term_part
|
89
|
+
@context_saver.context = {:term => @term, :global_term => @term }
|
90
|
+
debug :context, "Term #{s} is an allowed forward"
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
t
|
94
|
+
end
|
95
|
+
|
96
|
+
def term_continues?(s)
|
97
|
+
@term_part = "#{@term_part} #{s}"
|
98
|
+
t = @terms[@term_part]
|
99
|
+
r = @role_names[@term_part]
|
100
|
+
if t && (!r || !r[@term_part]) # Part of a term and not a complete role name
|
101
|
+
w = "term"
|
102
|
+
else
|
103
|
+
t = r
|
104
|
+
w = "role_name"
|
105
|
+
end
|
106
|
+
if t
|
107
|
+
debug :context, "Multi-word #{w} #{t[@term_part] ? 'ends at' : 'continues to'} #{@term_part.inspect}"
|
108
|
+
|
109
|
+
# Record the name of the full term and the underlying global term:
|
110
|
+
if t[@term_part]
|
111
|
+
@term = @term_part if t[@term_part]
|
112
|
+
@global_term = (t = t[@term_part]) == true ? @term_part : t
|
113
|
+
debug :context, "saving context #{@term}/#{@global_term}"
|
114
|
+
@context_saver.context = {:term => @term, :global_term => @global_term }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
t
|
118
|
+
end
|
119
|
+
|
120
|
+
def term_complete?
|
121
|
+
return true if @allowed_forward_terms.include?(@term)
|
122
|
+
return true if system_term(@term)
|
123
|
+
(t = @terms[@term] and t[@term]) or
|
124
|
+
(t = @role_names[@term] and t[@term])
|
125
|
+
end
|
126
|
+
|
127
|
+
def system_term(s)
|
128
|
+
false
|
129
|
+
end
|
130
|
+
|
131
|
+
def unit? s
|
132
|
+
@parser.unit? s
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
# Index the name by all prefixes
|
137
|
+
def index_name(index, name, value = true)
|
138
|
+
added = false
|
139
|
+
words = name.scan(/\w+/)
|
140
|
+
words.inject("") do |n, w|
|
141
|
+
# Index all prefixes up to the full term
|
142
|
+
n = n.empty? ? w : "#{n} #{w}"
|
143
|
+
index[n] ||= {}
|
144
|
+
added = true unless index[n][name]
|
145
|
+
index[n][name] = value # Save all possible completions of this prefix
|
146
|
+
n
|
147
|
+
end
|
148
|
+
added
|
30
149
|
end
|
31
150
|
end
|
32
151
|
|
33
|
-
class InputProxy
|
152
|
+
class InputProxy
|
34
153
|
attr_reader :context
|
35
154
|
|
36
155
|
def initialize(input, context)
|
@@ -64,7 +183,12 @@ module ActiveFacts
|
|
64
183
|
end
|
65
184
|
|
66
185
|
def context
|
67
|
-
@context ||=
|
186
|
+
@context ||= Context.new(self)
|
187
|
+
end
|
188
|
+
|
189
|
+
def unit?(s)
|
190
|
+
# puts "Asking whether #{s.inspect} is a unit"
|
191
|
+
true
|
68
192
|
end
|
69
193
|
|
70
194
|
def parse(input, options = {})
|
@@ -72,91 +196,18 @@ module ActiveFacts
|
|
72
196
|
super(input, options)
|
73
197
|
end
|
74
198
|
|
75
|
-
# Repeatedly parse rule_name until all input is consumed,
|
76
|
-
# returning an array of syntax trees for each definition.
|
77
199
|
def parse_all(input, rule_name = nil, &block)
|
78
200
|
self.root = rule_name if rule_name
|
79
201
|
|
80
202
|
@index = 0 # Byte offset to start next parse
|
81
203
|
self.consume_all_input = false
|
82
|
-
results = []
|
83
204
|
begin
|
84
205
|
node = parse(InputProxy.new(input, context), :index => @index)
|
85
206
|
return nil unless node
|
86
|
-
|
87
|
-
results << node if node
|
207
|
+
block.call(node) if block
|
88
208
|
end until self.index == @input_length
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
def definition(node)
|
93
|
-
name, ast = *node.value
|
94
|
-
kind, *value = *ast
|
95
|
-
|
96
|
-
begin
|
97
|
-
debug "CQL: Processing definition #{[kind, name].compact*" "}" do
|
98
|
-
case kind
|
99
|
-
when :vocabulary
|
100
|
-
[kind, name]
|
101
|
-
when :value_type
|
102
|
-
value_type_ast(name, value)
|
103
|
-
when :entity_type
|
104
|
-
supertypes = value.shift
|
105
|
-
entity_type_ast(name, supertypes, value)
|
106
|
-
when :fact_type
|
107
|
-
f = fact_type_ast(name, value)
|
108
|
-
when :unit
|
109
|
-
ast
|
110
|
-
when :constraint
|
111
|
-
ast
|
112
|
-
else
|
113
|
-
raise "CQL: internal error, unknown definition kind"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
rescue => e
|
118
|
-
raise "in #{kind.to_s.camelcase(true)} definition, #{e.message}:\n\t#{node.text_value}" +
|
119
|
-
(ENV['DEBUG'] =~ /\bexception\b/ ? "\nfrom\t"+e.backtrace*"\n\t" : "")
|
209
|
+
true
|
120
210
|
end
|
121
|
-
|
122
|
-
def value_type_ast(name, value)
|
123
|
-
# REVISIT: Massage/check value type here?
|
124
|
-
[:value_type, name, *value]
|
125
|
-
end
|
126
|
-
|
127
|
-
def entity_type_ast(name, supertypes, value)
|
128
|
-
#print "entity_type parameters for #{name}: "; p value
|
129
|
-
identification, mapping_pragmas, clauses = *value
|
130
|
-
clauses ||= []
|
131
|
-
|
132
|
-
# raise "Entity type clauses must all be fact types" if clauses.detect{|c| c[0] != :fact_clause }
|
133
|
-
|
134
|
-
[:entity_type, name, supertypes, identification, mapping_pragmas, clauses]
|
135
|
-
end
|
136
|
-
|
137
|
-
def fact_type_ast(name, value)
|
138
|
-
clauses, conditions = value
|
139
|
-
|
140
|
-
if conditions.empty? && includes_literals(clauses)
|
141
|
-
[:fact, nil, clauses]
|
142
|
-
elsif clauses.size == 1 &&
|
143
|
-
(popname = clauses[0][2]).size == 1 &&
|
144
|
-
popname[0].keys == [:word] &&
|
145
|
-
includes_literals(conditions)
|
146
|
-
[:fact, popname[0][:word], conditions]
|
147
|
-
else
|
148
|
-
[:fact_type, name, clauses, conditions]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def includes_literals(clauses)
|
153
|
-
clauses.detect do |clause|
|
154
|
-
raise "alternate clauses are not yet supported" if clause[0] == :"||"
|
155
|
-
fc, qualifiers, phrases, context_note = *clause
|
156
|
-
phrases.detect{|w| w[:literal]}
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
211
|
end
|
161
212
|
|
162
213
|
end
|