activefacts 0.6.0
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.
- data/History.txt +4 -0
- data/Manifest.txt +83 -0
- data/README.rdoc +81 -0
- data/Rakefile +41 -0
- data/bin/afgen +46 -0
- data/bin/cql +52 -0
- data/examples/CQL/Address.cql +46 -0
- data/examples/CQL/Blog.cql +54 -0
- data/examples/CQL/CompanyDirectorEmployee.cql +51 -0
- data/examples/CQL/Death.cql +16 -0
- data/examples/CQL/Genealogy.cql +95 -0
- data/examples/CQL/Marriage.cql +18 -0
- data/examples/CQL/Metamodel.cql +238 -0
- data/examples/CQL/MultiInheritance.cql +19 -0
- data/examples/CQL/OilSupply.cql +47 -0
- data/examples/CQL/Orienteering.cql +108 -0
- data/examples/CQL/PersonPlaysGame.cql +17 -0
- data/examples/CQL/SchoolActivities.cql +31 -0
- data/examples/CQL/SimplestUnary.cql +12 -0
- data/examples/CQL/SubtypePI.cql +32 -0
- data/examples/CQL/Warehousing.cql +99 -0
- data/examples/CQL/WindowInRoomInBldg.cql +22 -0
- data/lib/activefacts.rb +10 -0
- data/lib/activefacts/api.rb +25 -0
- data/lib/activefacts/api/concept.rb +384 -0
- data/lib/activefacts/api/constellation.rb +106 -0
- data/lib/activefacts/api/entity.rb +239 -0
- data/lib/activefacts/api/instance.rb +54 -0
- data/lib/activefacts/api/numeric.rb +158 -0
- data/lib/activefacts/api/role.rb +94 -0
- data/lib/activefacts/api/standard_types.rb +67 -0
- data/lib/activefacts/api/support.rb +59 -0
- data/lib/activefacts/api/value.rb +122 -0
- data/lib/activefacts/api/vocabulary.rb +120 -0
- data/lib/activefacts/cql.rb +31 -0
- data/lib/activefacts/cql/CQLParser.treetop +104 -0
- data/lib/activefacts/cql/Concepts.treetop +112 -0
- data/lib/activefacts/cql/DataTypes.treetop +66 -0
- data/lib/activefacts/cql/Expressions.treetop +113 -0
- data/lib/activefacts/cql/FactTypes.treetop +185 -0
- data/lib/activefacts/cql/Language/English.treetop +92 -0
- data/lib/activefacts/cql/LexicalRules.treetop +169 -0
- data/lib/activefacts/cql/Rakefile +6 -0
- data/lib/activefacts/cql/parser.rb +88 -0
- data/lib/activefacts/generate/absorption.rb +87 -0
- data/lib/activefacts/generate/cql.rb +441 -0
- data/lib/activefacts/generate/cql/html.rb +397 -0
- data/lib/activefacts/generate/null.rb +19 -0
- data/lib/activefacts/generate/ordered.rb +557 -0
- data/lib/activefacts/generate/ruby.rb +326 -0
- data/lib/activefacts/generate/sql/server.rb +164 -0
- data/lib/activefacts/generate/text.rb +21 -0
- data/lib/activefacts/input/cql.rb +1268 -0
- data/lib/activefacts/input/orm.rb +926 -0
- data/lib/activefacts/persistence.rb +1 -0
- data/lib/activefacts/persistence/composition.rb +653 -0
- data/lib/activefacts/support.rb +51 -0
- data/lib/activefacts/version.rb +3 -0
- data/lib/activefacts/vocabulary.rb +6 -0
- data/lib/activefacts/vocabulary/extensions.rb +343 -0
- data/lib/activefacts/vocabulary/metamodel.rb +303 -0
- data/script/txt2html +71 -0
- data/spec/absorption_spec.rb +95 -0
- data/spec/api/autocounter.rb +82 -0
- data/spec/api/constellation.rb +130 -0
- data/spec/api/entity_type.rb +101 -0
- data/spec/api/instance.rb +428 -0
- data/spec/api/roles.rb +122 -0
- data/spec/api/value_type.rb +112 -0
- data/spec/api_spec.rb +14 -0
- data/spec/cql_cql_spec.rb +58 -0
- data/spec/cql_parse_spec.rb +31 -0
- data/spec/cql_ruby_spec.rb +60 -0
- data/spec/cql_sql_spec.rb +54 -0
- data/spec/cql_symbol_tables_spec.rb +259 -0
- data/spec/cql_unit_spec.rb +336 -0
- data/spec/cqldump_spec.rb +169 -0
- data/spec/norma_cql_spec.rb +48 -0
- data/spec/norma_ruby_spec.rb +50 -0
- data/spec/norma_sql_spec.rb +45 -0
- data/spec/norma_tables_spec.rb +94 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +173 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts CQL loader.
|
3
|
+
# Copyright (c) 2007 Clifford Heath. Read the LICENSE file.
|
4
|
+
#
|
5
|
+
require 'rubygems'
|
6
|
+
require 'polyglot'
|
7
|
+
require 'activefacts/support'
|
8
|
+
require 'activefacts/input/cql'
|
9
|
+
require 'activefacts/generate/ruby'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
# Extend the generated parser:
|
13
|
+
class CQLLoader
|
14
|
+
# This load method for Polyglot tells it how to _require_ a CQL file.
|
15
|
+
# The CQL file is parsed to a vocabulary constellation, which is generated
|
16
|
+
# to Ruby code and eval'd, making the generated classes available.
|
17
|
+
def self.load(file)
|
18
|
+
debug "Loading #{file}" do
|
19
|
+
vocabulary = ActiveFacts::Input::CQL.readfile(file)
|
20
|
+
|
21
|
+
ruby = StringIO.new
|
22
|
+
@dumper = ActiveFacts::Generate::RUBY.new(vocabulary.constellation)
|
23
|
+
@dumper.generate(ruby)
|
24
|
+
ruby.rewind
|
25
|
+
eval ruby.read, ::TOPLEVEL_BINDING
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Polyglot.register('cql', CQLLoader)
|
31
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
grammar CQL
|
3
|
+
include LexicalRules
|
4
|
+
include Language # One of the language modules provides this module
|
5
|
+
include Expressions
|
6
|
+
include Concepts
|
7
|
+
include DataTypes
|
8
|
+
include FactTypes
|
9
|
+
|
10
|
+
rule cql_file
|
11
|
+
s seq:definition*
|
12
|
+
{
|
13
|
+
def definitions
|
14
|
+
seq.elements.map{|e|
|
15
|
+
e.value rescue $stderr.puts "Can't call value() on #{e.inspect}"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
# Each definition has a value() method that returns an array like
|
22
|
+
# either [name, [kind, definition]] or [name, kind]:
|
23
|
+
rule definition
|
24
|
+
vocabulary_definition
|
25
|
+
/ import_definition
|
26
|
+
/ constraint
|
27
|
+
/ concept
|
28
|
+
end
|
29
|
+
|
30
|
+
rule vocabulary_definition
|
31
|
+
s vocabulary S id s ';' s
|
32
|
+
{
|
33
|
+
def value
|
34
|
+
[ id.text_value, [ :vocabulary ] ]
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
rule import_definition
|
40
|
+
s import S id alias_list ';' s
|
41
|
+
{
|
42
|
+
def value
|
43
|
+
puts "import #{id.text_value}: not implemented"
|
44
|
+
[ id.text_value, [ :import ], alias_list.value ]
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
# REVISIT: Need a way to define equivalent readings for fact types here (and in the metamodel)
|
50
|
+
rule alias_list
|
51
|
+
( s ',' s alias S aliase_from:id S as S alias_to:id s )*
|
52
|
+
{
|
53
|
+
def value
|
54
|
+
elements.inject({}){|h, e| h[e.aliase_from.text_value] = e.alias_to; h }
|
55
|
+
end
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
rule constraint
|
60
|
+
subset_constraint /
|
61
|
+
equality_constraint /
|
62
|
+
set_constraint /
|
63
|
+
presence_constraint
|
64
|
+
# REVISIT: / value_constraint
|
65
|
+
end
|
66
|
+
|
67
|
+
# presence constraint:
|
68
|
+
rule presence_constraint
|
69
|
+
s 'each' s ('combination' S)? role_list s 'occurs' s quantifier s 'time' s 'in' s
|
70
|
+
readings_list s
|
71
|
+
';' s
|
72
|
+
{ def value; [ nil, [ :constraint, :presence, role_list.roles, quantifier.value, readings_list.value ] ]; end }
|
73
|
+
end
|
74
|
+
|
75
|
+
rule subset_constraint
|
76
|
+
s readings s only s if s r2:readings s ';' s
|
77
|
+
{ def value; [ nil, [ :constraint, :subset, readings.value, r2.value ] ]; end }
|
78
|
+
end
|
79
|
+
|
80
|
+
# set (exclusion, mandatory exclusion, complex equality) constraint
|
81
|
+
rule set_constraint
|
82
|
+
s 'for' s 'each' s role_list s quantifier s 'of' s 'these' s 'holds' s ':' s
|
83
|
+
readings_list s
|
84
|
+
';' s
|
85
|
+
{ def value; [ nil, [ :constraint, :set, role_list.roles, quantifier.value, *readings_list.value ] ]; end }
|
86
|
+
end
|
87
|
+
|
88
|
+
rule equality_constraint
|
89
|
+
s readings s tail:( if s and s only s if s readings s)+ ';' s
|
90
|
+
{ def value; [ nil, [ :constraint, :equality, *([readings.value] + tail.elements.map{|e| e.readings.value }) ] ]; end }
|
91
|
+
end
|
92
|
+
|
93
|
+
rule readings_list
|
94
|
+
readings tail:( ',' s readings )*
|
95
|
+
{ def value; [readings.value]+tail.elements.map{|e| e.readings.value }; end }
|
96
|
+
end
|
97
|
+
|
98
|
+
rule readings
|
99
|
+
reading s tail:( and s reading s )*
|
100
|
+
{ def value; [reading.value]+tail.elements.map{|e| e.reading.value }; end }
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module CQL
|
3
|
+
grammar Concepts
|
4
|
+
rule concept
|
5
|
+
entity_type
|
6
|
+
/ data_type
|
7
|
+
/ named_fact_type
|
8
|
+
/ anonymous_fact_type
|
9
|
+
end
|
10
|
+
|
11
|
+
rule entity_type
|
12
|
+
s name:id s
|
13
|
+
sup:(basetype / subtype)
|
14
|
+
ec:entity_conditions?
|
15
|
+
';' s
|
16
|
+
{
|
17
|
+
def value
|
18
|
+
[ name.text_value, [ :entity_type, sup.supers, sup.identifier, ec.empty? ? nil : ec.conditions ] ]
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
rule subtype
|
24
|
+
subtype_prefix supertype_list ident:identification?
|
25
|
+
{
|
26
|
+
def supers; supertype_list.value; end
|
27
|
+
def identifier; ident.empty? ? nil : ident.value; end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
rule supertype_list
|
32
|
+
primary:id s
|
33
|
+
alternate_supertypes:( ',' s !identified_by name:id s )*
|
34
|
+
{ def value
|
35
|
+
[primary.text_value]+alternate_supertypes.elements.map{|sup| sup.name.text_value}
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
rule basetype
|
41
|
+
is s identification
|
42
|
+
{ def supers; [] end
|
43
|
+
def identifier; identification.value; end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
rule identification
|
48
|
+
# REVISIT: Consider distinguishing "-Id" from just "Id", and not prepending the entity type name if no "-"
|
49
|
+
identified_by its s id s # Reference Mode
|
50
|
+
{ def value; {:mode => id.text_value }; end }
|
51
|
+
/
|
52
|
+
identified_by role_list
|
53
|
+
{ def value; {:roles => role_list.roles }; end }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Identified by roles... also used for constraints, beware
|
57
|
+
rule role_list
|
58
|
+
head:role_player s tail:( ( and S / ',' s ) role:role_player s )*
|
59
|
+
{
|
60
|
+
def roles
|
61
|
+
[head.value] + tail.elements.map{|i| i.role.value}
|
62
|
+
end
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
# We can't tell which word is an adjective and which is a concept here.
|
67
|
+
# The concept might be forward-referenced, but not if adjectives are used.
|
68
|
+
# REVISIT: This accepts double-adjective expressions (three words) but they don't work elsewhere
|
69
|
+
rule lead_adj
|
70
|
+
role_player_id '-'
|
71
|
+
end
|
72
|
+
|
73
|
+
rule trail_adj
|
74
|
+
'-' role_player_id
|
75
|
+
end
|
76
|
+
|
77
|
+
rule role_player
|
78
|
+
l:lead_adj? tail:(s role_player_id)+ s t:trail_adj?
|
79
|
+
{
|
80
|
+
def value
|
81
|
+
(l.empty? ? [] : [l.role_player_id.text_value]) +
|
82
|
+
tail.elements.map{|e| e.role_player_id.text_value } +
|
83
|
+
(t.empty? ? [] : [t.role_player_id.text_value])
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
rule role_player_id
|
89
|
+
!(role_list_sep / quantifier) id
|
90
|
+
end
|
91
|
+
|
92
|
+
rule role_list_sep
|
93
|
+
(where / and / 'occurs')
|
94
|
+
end
|
95
|
+
|
96
|
+
rule reference_mode
|
97
|
+
# REVISIT: Adopt ORM2-style reference mode patterns here
|
98
|
+
'(' s '.' s mode_name:id s ')' s
|
99
|
+
end
|
100
|
+
|
101
|
+
rule entity_conditions
|
102
|
+
(':' / where) s c:conditions?
|
103
|
+
{
|
104
|
+
def conditions
|
105
|
+
c.empty? ? [] : c.condition_list
|
106
|
+
end
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module CQL
|
3
|
+
grammar DataTypes
|
4
|
+
rule data_type
|
5
|
+
s name:id
|
6
|
+
( s '=' s / defined_as )
|
7
|
+
base:id s
|
8
|
+
'(' s tpl:type_parameter_list? ')' s
|
9
|
+
u0:(!restricted u1:unit s)?
|
10
|
+
r:restriction?
|
11
|
+
s ';' s
|
12
|
+
{
|
13
|
+
def defined_type
|
14
|
+
[
|
15
|
+
:data_type,
|
16
|
+
base.text_value,
|
17
|
+
tpl.empty? ? [] : tpl.value,
|
18
|
+
!u0.empty? ? u0.u1.text_value : nil,
|
19
|
+
!r.empty? ? r.ranges : [],
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def value
|
24
|
+
[ name.text_value,
|
25
|
+
defined_type
|
26
|
+
]
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
rule type_parameter_list
|
32
|
+
head:number s tail:( ',' s number s )*
|
33
|
+
{
|
34
|
+
def value
|
35
|
+
[head.value] + tail.elements.map{|i| i.number.value}
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
rule unit
|
41
|
+
unit_name:id ('^' '-'? [0-9])?
|
42
|
+
end
|
43
|
+
|
44
|
+
rule restriction
|
45
|
+
restricted s to s range_list s unit?
|
46
|
+
{
|
47
|
+
def ranges
|
48
|
+
range_list.ranges
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
rule range_list
|
54
|
+
'{' s
|
55
|
+
head:range s tail:( ',' s range )*
|
56
|
+
'}' s
|
57
|
+
{
|
58
|
+
def ranges
|
59
|
+
[head.value] + tail.elements.map{|e| e.range.value }
|
60
|
+
end
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module CQL
|
3
|
+
grammar Expressions
|
4
|
+
rule comparison
|
5
|
+
e1:expression s comparator s e2:expression
|
6
|
+
{
|
7
|
+
def body
|
8
|
+
[ comparator.text_value,
|
9
|
+
e1.value,
|
10
|
+
e2.value
|
11
|
+
]
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
rule comparator
|
17
|
+
'<=' / '<' / '=' / '>=' / '>'
|
18
|
+
# REVISIT: These words occur in readings, find alternates:
|
19
|
+
# / matches / includes
|
20
|
+
end
|
21
|
+
|
22
|
+
rule expression
|
23
|
+
sum
|
24
|
+
end
|
25
|
+
|
26
|
+
rule sum
|
27
|
+
t0:term s tail:( o:add_op s t1:term s )*
|
28
|
+
{
|
29
|
+
def value
|
30
|
+
return t0.value if tail.empty?
|
31
|
+
[ :"+",
|
32
|
+
*([t0.value] +
|
33
|
+
tail.elements.map{|e|
|
34
|
+
e.o.text_value == '-' ? [ :"-", e.t1.value ] : e.t1.value
|
35
|
+
}
|
36
|
+
)
|
37
|
+
]
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
rule add_op
|
43
|
+
'+' / '-'
|
44
|
+
end
|
45
|
+
|
46
|
+
rule term
|
47
|
+
f0:factor s tail:( o:mul_op s f1:factor s )*
|
48
|
+
{
|
49
|
+
def value
|
50
|
+
return f0.value if tail.empty?
|
51
|
+
[ :"*",
|
52
|
+
*([f0.value] +
|
53
|
+
tail.elements.map{|e|
|
54
|
+
e.o.text_value != '*' ? [ :"-", e.f1.value ] : e.f1.value
|
55
|
+
}
|
56
|
+
)
|
57
|
+
]
|
58
|
+
end
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
rule factor
|
63
|
+
literal u:unit? s
|
64
|
+
{ def value
|
65
|
+
u.empty? ? literal.value : [ literal.value, u.text_value ]
|
66
|
+
end
|
67
|
+
}
|
68
|
+
/ derived_variable
|
69
|
+
/ '(' s sum s ')' s { def value; sum.value; end }
|
70
|
+
end
|
71
|
+
|
72
|
+
rule derived_variable
|
73
|
+
variable s p:function_call*
|
74
|
+
{
|
75
|
+
def value
|
76
|
+
r = variable.value
|
77
|
+
# Apply the function_call operators in order:
|
78
|
+
p.elements.each{|p| r = [ p.value, r ] }
|
79
|
+
r
|
80
|
+
end
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
rule variable
|
85
|
+
id0:id o0:( !defined_as s id1:id )?
|
86
|
+
{
|
87
|
+
def value
|
88
|
+
# Variable names may consist of one or two words (optional adjective and a noun):
|
89
|
+
r = [ :variable, id0.text_value ]
|
90
|
+
r += [ o0.id1.text_value ] unless o0.empty?
|
91
|
+
r
|
92
|
+
end
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
rule function_call
|
97
|
+
'.' s func:id s param_list:( '(' s params:( p0:expression s tail:( ',' s p1:expression s )* )? ')' s )?
|
98
|
+
{
|
99
|
+
def value
|
100
|
+
r = [ :"(", func.text_value ]
|
101
|
+
return r if param_list.empty? || param_list.params.empty?
|
102
|
+
r += [ param_list.params.p0.value ]
|
103
|
+
param_list.params.tail.elements.each{|e|
|
104
|
+
r += [ e.p1.value ]
|
105
|
+
}
|
106
|
+
r
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module CQL
|
3
|
+
grammar FactTypes
|
4
|
+
rule named_fact_type
|
5
|
+
s name:id ( s '=' s / defined_as / s is s where )
|
6
|
+
anonymous_fact_type
|
7
|
+
{
|
8
|
+
def value
|
9
|
+
f = anonymous_fact_type.value
|
10
|
+
f[0] = name.text_value
|
11
|
+
f
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
rule anonymous_fact_type
|
17
|
+
f0:fact_clause
|
18
|
+
ftail:( (',' / and ) s f1:fact_clause s )*
|
19
|
+
ctail:( (':' / where) s c:conditions s)?
|
20
|
+
returning_clause?
|
21
|
+
s ';' s
|
22
|
+
{
|
23
|
+
def value
|
24
|
+
[
|
25
|
+
nil, # Anonymous fact type
|
26
|
+
[
|
27
|
+
:fact_type,
|
28
|
+
[ f0.body, *ftail.elements.map{|e| e.f1.body } ],
|
29
|
+
!ctail.empty? ? ctail.c.condition_list : []
|
30
|
+
]
|
31
|
+
]
|
32
|
+
end
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
rule returning_clause
|
37
|
+
returning return (',' return)*
|
38
|
+
end
|
39
|
+
|
40
|
+
rule return
|
41
|
+
by order 'REVISIT: return'
|
42
|
+
end
|
43
|
+
|
44
|
+
rule conditions
|
45
|
+
head:condition s tail:( (',' s / and S) next:condition s )*
|
46
|
+
{
|
47
|
+
def condition_list
|
48
|
+
[head.value] + tail.elements.map{|i| i.next.value}
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
rule condition
|
54
|
+
head:clause s
|
55
|
+
# tail:(or S alternate:clause s )*
|
56
|
+
{
|
57
|
+
def value
|
58
|
+
# if tail.elements.size == 0
|
59
|
+
head.clause
|
60
|
+
# else
|
61
|
+
# [:"||", head.clause] + tail.elements.map{|i| i.alternate.clause}
|
62
|
+
# end
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
rule clause
|
68
|
+
(comparison / fact_clause)
|
69
|
+
{
|
70
|
+
def clause
|
71
|
+
self.body
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
rule fact_clause
|
77
|
+
s q:qualifier? s reading s p:post_qualifiers? s
|
78
|
+
{
|
79
|
+
def body
|
80
|
+
[ :fact_clause,
|
81
|
+
(q.empty? ? [] : [ q.text_value ]) +
|
82
|
+
(p.empty? ? [] : p.list),
|
83
|
+
reading.value
|
84
|
+
]
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
rule qualifier
|
90
|
+
maybe / definitely
|
91
|
+
end
|
92
|
+
|
93
|
+
rule post_qualifiers
|
94
|
+
'[' s q0:post_qualifier tail:( s ',' s q1:post_qualifier )* s ']' s
|
95
|
+
{
|
96
|
+
def list
|
97
|
+
[q0.text_value] + tail.elements.map{|e| e.q1.text_value}
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
rule post_qualifier
|
103
|
+
static / transient / intransitive / transitive / acyclic / symmetric
|
104
|
+
end
|
105
|
+
|
106
|
+
rule reading
|
107
|
+
subtype_invocation
|
108
|
+
/
|
109
|
+
role+
|
110
|
+
{
|
111
|
+
def value
|
112
|
+
elements.map{|r| r.value}
|
113
|
+
end
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
# REVISIT: This allows invocation from subtype to supertype. We need the reverse as well (Employee is a Manager).
|
118
|
+
# Now that subtyping fact types have readings created during compilation, perhaps these custom rules can be removed?
|
119
|
+
rule subtype_invocation
|
120
|
+
(('some'/'that') S)? subtype:id s subtype_prefix (('some'/'that') S)? supertype:id
|
121
|
+
{
|
122
|
+
def value
|
123
|
+
[{:subtype => subtype.text_value, :supertype => supertype.text_value }]
|
124
|
+
# [subtype.text_value, "is", "a", "subtype", "of", supertype.text_value].map{|w| {:word => w}}
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
# This is the rule that causes most back-tracking. I think you can see why.
|
130
|
+
# When we have an expression, we will come down here perhaps multiple times,
|
131
|
+
# but find no way out as soon as we hit the trailing non_role.
|
132
|
+
rule role
|
133
|
+
q:quantifier?
|
134
|
+
adj0:(a:role_word '-' s)?
|
135
|
+
player:role_word !'-' s?
|
136
|
+
adj1:( '-' a:(a:role_word s)? )?
|
137
|
+
func:function_call?
|
138
|
+
role_name:( '(' s as S r:id s ')' s )?
|
139
|
+
lr:( literal / restriction )?
|
140
|
+
!non_role
|
141
|
+
{
|
142
|
+
def value
|
143
|
+
r = {}
|
144
|
+
quantifier = !q.empty? && q.value # "some" quantifier has nil value
|
145
|
+
|
146
|
+
r[:quantifier] = quantifier if quantifier
|
147
|
+
r[:leading_adjective] = adj0.a.text_value unless adj0.empty?
|
148
|
+
|
149
|
+
r[:word] = player.text_value
|
150
|
+
|
151
|
+
r[:trailing_adjective] = adj1.a.a.text_value unless adj1.empty?
|
152
|
+
r[:function] = func.value if !func.empty?
|
153
|
+
r[:role_name] = role_name.r.text_value unless role_name.empty?
|
154
|
+
r[:restriction] = lr.ranges if !lr.empty? && lr.respond_to?(:ranges)
|
155
|
+
r[:literal] = lr.value if !lr.empty? && lr.respond_to?(:value)
|
156
|
+
|
157
|
+
r
|
158
|
+
end
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
rule non_role
|
163
|
+
# Any of these is illegal in or following a reading:
|
164
|
+
comparator
|
165
|
+
/ add_op
|
166
|
+
/ mul_op
|
167
|
+
end
|
168
|
+
|
169
|
+
rule role_word
|
170
|
+
!non_role_word id
|
171
|
+
end
|
172
|
+
|
173
|
+
rule non_role_word
|
174
|
+
# These words are illegal in (but maybe ok following) a reading where a role word is expected:
|
175
|
+
and
|
176
|
+
/ if
|
177
|
+
/ only
|
178
|
+
/ or
|
179
|
+
/ quantifier
|
180
|
+
/ restriction
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|