activefacts 0.7.3 → 0.8.5

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 (94) hide show
  1. data/LICENSE +19 -0
  2. data/Manifest.txt +24 -2
  3. data/Rakefile +25 -3
  4. data/bin/afgen +1 -1
  5. data/bin/cql +13 -2
  6. data/css/offline.css +3 -0
  7. data/css/orm2.css +24 -0
  8. data/css/print.css +8 -0
  9. data/css/style-print.css +357 -0
  10. data/css/style.css +387 -0
  11. data/download.html +85 -0
  12. data/examples/CQL/Address.cql +3 -3
  13. data/examples/CQL/Blog.cql +13 -14
  14. data/examples/CQL/CompanyDirectorEmployee.cql +4 -4
  15. data/examples/CQL/Death.cql +3 -2
  16. data/examples/CQL/Genealogy.cql +13 -11
  17. data/examples/CQL/Marriage.cql +2 -2
  18. data/examples/CQL/Metamodel.cql +136 -93
  19. data/examples/CQL/MultiInheritance.cql +2 -2
  20. data/examples/CQL/OilSupply.cql +14 -10
  21. data/examples/CQL/Orienteering.cql +22 -19
  22. data/examples/CQL/PersonPlaysGame.cql +3 -2
  23. data/examples/CQL/SchoolActivities.cql +4 -2
  24. data/examples/CQL/SimplestUnary.cql +1 -1
  25. data/examples/CQL/SubtypePI.cql +6 -7
  26. data/examples/CQL/Warehousing.cql +16 -19
  27. data/examples/CQL/unit.cql +584 -0
  28. data/examples/index.html +276 -0
  29. data/examples/intro.html +497 -0
  30. data/examples/local.css +20 -0
  31. data/index.html +96 -0
  32. data/lib/activefacts/api/concept.rb +48 -46
  33. data/lib/activefacts/api/constellation.rb +43 -23
  34. data/lib/activefacts/api/entity.rb +2 -2
  35. data/lib/activefacts/api/instance.rb +6 -2
  36. data/lib/activefacts/api/instance_index.rb +5 -0
  37. data/lib/activefacts/api/value.rb +8 -2
  38. data/lib/activefacts/api/vocabulary.rb +15 -10
  39. data/lib/activefacts/cql/CQLParser.treetop +109 -88
  40. data/lib/activefacts/cql/Concepts.treetop +32 -10
  41. data/lib/activefacts/cql/Context.treetop +34 -0
  42. data/lib/activefacts/cql/Expressions.treetop +9 -9
  43. data/lib/activefacts/cql/FactTypes.treetop +30 -31
  44. data/lib/activefacts/cql/Language/English.treetop +50 -0
  45. data/lib/activefacts/cql/LexicalRules.treetop +2 -1
  46. data/lib/activefacts/cql/Terms.treetop +117 -0
  47. data/lib/activefacts/cql/ValueTypes.treetop +152 -0
  48. data/lib/activefacts/cql/compiler.rb +1718 -0
  49. data/lib/activefacts/cql/parser.rb +124 -57
  50. data/lib/activefacts/generate/absorption.rb +1 -1
  51. data/lib/activefacts/generate/cql.rb +111 -100
  52. data/lib/activefacts/generate/cql/html.rb +5 -5
  53. data/lib/activefacts/generate/oo.rb +3 -3
  54. data/lib/activefacts/generate/ordered.rb +51 -19
  55. data/lib/activefacts/generate/ruby.rb +10 -8
  56. data/lib/activefacts/generate/sql/mysql.rb +14 -10
  57. data/lib/activefacts/generate/sql/server.rb +29 -24
  58. data/lib/activefacts/input/cql.rb +9 -1264
  59. data/lib/activefacts/input/orm.rb +213 -200
  60. data/lib/activefacts/persistence/columns.rb +11 -10
  61. data/lib/activefacts/persistence/index.rb +15 -18
  62. data/lib/activefacts/persistence/reference.rb +17 -17
  63. data/lib/activefacts/persistence/tables.rb +50 -51
  64. data/lib/activefacts/version.rb +1 -1
  65. data/lib/activefacts/vocabulary/extensions.rb +79 -8
  66. data/lib/activefacts/vocabulary/metamodel.rb +183 -114
  67. data/spec/absorption_ruby_spec.rb +99 -0
  68. data/spec/absorption_spec.rb +3 -4
  69. data/spec/api/constellation.rb +1 -1
  70. data/spec/api/entity_type.rb +3 -1
  71. data/spec/api/instance.rb +4 -2
  72. data/spec/api/roles.rb +8 -6
  73. data/spec/api_spec.rb +1 -2
  74. data/spec/cql/context_spec.rb +71 -0
  75. data/spec/cql/samples_spec.rb +154 -0
  76. data/spec/cql/unit_spec.rb +375 -0
  77. data/spec/cql_cql_spec.rb +31 -21
  78. data/spec/cql_mysql_spec.rb +70 -0
  79. data/spec/cql_parse_spec.rb +15 -9
  80. data/spec/cql_ruby_spec.rb +27 -13
  81. data/spec/cql_sql_spec.rb +42 -16
  82. data/spec/cql_symbol_tables_spec.rb +2 -3
  83. data/spec/cqldump_spec.rb +7 -7
  84. data/spec/helpers/file_matcher.rb +39 -0
  85. data/spec/norma_cql_spec.rb +20 -12
  86. data/spec/norma_ruby_spec.rb +6 -3
  87. data/spec/norma_sql_spec.rb +6 -3
  88. data/spec/norma_tables_spec.rb +6 -4
  89. data/spec/spec_helper.rb +27 -8
  90. data/status.html +69 -0
  91. data/why.html +60 -0
  92. metadata +34 -11
  93. data/lib/activefacts/cql/DataTypes.treetop +0 -81
  94. data/spec/cql_unit_spec.rb +0 -330
@@ -5,106 +5,127 @@
5
5
  # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
6
  #
7
7
  module ActiveFacts
8
- grammar CQL
9
- include LexicalRules
10
- include Language # One of the language modules provides this module
11
- include Expressions
12
- include Concepts
13
- include DataTypes
14
- include FactTypes
8
+ module CQL
9
+ grammar CQL
10
+ include LexicalRules
11
+ include Language # One of the language modules provides this module
12
+ include Expressions
13
+ include Terms
14
+ include Concepts
15
+ include ValueTypes
16
+ include FactTypes
17
+ include Context
15
18
 
16
- rule cql_file
17
- s seq:definition*
18
- {
19
- def definitions
20
- seq.elements.map{|e|
21
- e.value rescue $stderr.puts "Can't call value() on #{e.inspect}"
22
- }
23
- end
24
- }
25
- end
19
+ rule cql_file
20
+ s seq:definition*
21
+ {
22
+ def definitions
23
+ seq.elements.map{|e|
24
+ e.value rescue $stderr.puts "Can't call value() on #{e.inspect}"
25
+ }
26
+ end
27
+ }
28
+ end
26
29
 
27
- # Each definition has a value() method that returns an array like
28
- # either [name, [kind, definition]] or [name, kind]:
29
- rule definition
30
- vocabulary_definition
31
- / import_definition
32
- / constraint
33
- / concept
34
- end
30
+ # Each definition has a value() method that returns an array like
31
+ # either [name, [kind, definition]] or [name, kind]:
32
+ rule definition
33
+ vocabulary_definition
34
+ / import_definition
35
+ / prescan
36
+ / constraint
37
+ / unit_definition
38
+ / concept
39
+ end
35
40
 
36
- rule vocabulary_definition
37
- s vocabulary S id s ';' s
38
- {
39
- def value
40
- [ id.text_value, [ :vocabulary ] ]
41
- end
42
- }
43
- end
41
+ rule vocabulary_definition
42
+ s vocabulary S id s ';' s &{|e| input.context.vocabulary(e[3].text_value); true }
43
+ {
44
+ def value
45
+ [ id.value, [ :vocabulary ] ]
46
+ end
47
+ }
48
+ end
44
49
 
45
- rule import_definition
46
- s import S id alias_list ';' s
47
- {
48
- def value
49
- puts "import #{id.text_value}: not implemented"
50
- [ id.text_value, [ :import ], alias_list.value ]
51
- end
52
- }
53
- end
50
+ rule import_definition
51
+ s import S id alias_list ';' s
52
+ {
53
+ def value
54
+ puts "import #{id.value}: not implemented"
55
+ [ id.value, [ :import ], alias_list.value ]
56
+ end
57
+ }
58
+ end
54
59
 
55
- # REVISIT: Need a way to define equivalent readings for fact types here (and in the metamodel)
56
- rule alias_list
57
- ( s ',' s alias S aliase_from:id S as S alias_to:id s )*
58
- {
59
- def value
60
- elements.inject({}){|h, e| h[e.aliase_from.text_value] = e.alias_to; h }
61
- end
62
- }
63
- end
60
+ # REVISIT: Need a way to define equivalent readings for fact types here (and in the metamodel)
61
+ rule alias_list
62
+ ( s ',' s alias S aliased_from:id S as S alias_to:id s )*
63
+ {
64
+ def value
65
+ elements.inject({}){|h, e| h[e.aliased_from.value] = e.alias_to; h }
66
+ end
67
+ }
68
+ end
64
69
 
65
- rule constraint
66
- subset_constraint /
67
- equality_constraint /
68
- set_constraint /
69
- presence_constraint
70
- # REVISIT: / value_constraint
71
- end
70
+ rule constraint
71
+ subset_constraint /
72
+ equality_constraint /
73
+ set_constraint /
74
+ presence_constraint
75
+ # REVISIT: / value_constraint
76
+ end
72
77
 
73
- # presence constraint:
74
- rule presence_constraint
75
- s 'each' s ('combination' S)? role_list s 'occurs' s quantifier s 'time' s 'in' s
76
- readings_list s
77
- ';' s
78
- { def value; [ nil, [ :constraint, :presence, role_list.roles, quantifier.value, readings_list.value ] ]; end }
79
- end
78
+ # presence constraint:
79
+ rule presence_constraint
80
+ s 'each' s ('combination' S)? role_list s 'occurs' s quantifier s 'time' s 'in' s
81
+ readings_list s
82
+ c:context? ';' s
83
+ { def value; [ nil, [ :constraint, :presence, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value ] ]; end }
84
+ end
80
85
 
81
- rule subset_constraint
82
- s readings s only s if s r2:readings s ';' s
83
- { def value; [ nil, [ :constraint, :subset, readings.value, r2.value ] ]; end }
84
- end
86
+ # set (exclusion, mandatory exclusion, complex equality) constraint
87
+ rule set_constraint
88
+ s 'for' s 'each' s role_list s quantifier s 'of' s 'these' s 'holds' s ':' s
89
+ readings_list s
90
+ c:context? ';' s
91
+ { def value; [ nil, [ :constraint, :set, role_list.roles, quantifier.value, readings_list.value, c.empty? ? nil : c.value ] ]; end }
92
+ /
93
+ s either? s r1:readings s or s r2:readings exclusion:(but s not s both s)? c:context? ';' s
94
+ { def value;
95
+ [ nil, [ :constraint, :set,
96
+ nil, # No roles names, rely on the join
97
+ exclusion.text_value.empty? ?
98
+ [1, nil] : # At least one (meaning 1 or 2/more)
99
+ [1,1], # Exactly one (1 and only 1)
100
+ [r1.value, r2.value],
101
+ c.empty? ? nil : c.value
102
+ ] ];
103
+ end
104
+ }
105
+ end
85
106
 
86
- # set (exclusion, mandatory exclusion, complex equality) constraint
87
- rule set_constraint
88
- s 'for' s 'each' s role_list s quantifier s 'of' s 'these' s 'holds' s ':' s
89
- readings_list s
90
- ';' s
91
- { def value; [ nil, [ :constraint, :set, role_list.roles, quantifier.value, *readings_list.value ] ]; end }
92
- end
107
+ rule subset_constraint
108
+ s readings s only s if s r2:readings s
109
+ c:context? ';' s
110
+ { def value; [ nil, [ :constraint, :subset, [readings.value, r2.value], c.empty? ? nil : c.value ] ]; end }
111
+ end
93
112
 
94
- rule equality_constraint
95
- s readings s tail:( if s and s only s if s readings s)+ ';' s
96
- { def value; [ nil, [ :constraint, :equality, *([readings.value] + tail.elements.map{|e| e.readings.value }) ] ]; end }
97
- end
113
+ rule equality_constraint
114
+ s readings s tail:( if s and s only s if s readings s)+
115
+ c:context? ';' s
116
+ { def value; [ nil, [ :constraint, :equality, [readings.value] + tail.elements.map{|e| e.readings.value }, c.empty? ? nil : c.value ]]; end }
117
+ end
98
118
 
99
- rule readings_list
100
- readings tail:( ',' s readings )*
101
- { def value; [readings.value]+tail.elements.map{|e| e.readings.value }; end }
102
- end
119
+ rule readings_list
120
+ readings tail:( ',' s readings )*
121
+ { def value; [readings.value]+tail.elements.map{|e| e.readings.value }; end }
122
+ end
103
123
 
104
- rule readings
105
- reading s tail:( and s reading s )*
106
- { def value; [reading.value]+tail.elements.map{|e| e.reading.value }; end }
107
- end
124
+ rule readings
125
+ reading s tail:( and s reading s )*
126
+ { def value; [reading.value]+tail.elements.map{|e| e.reading.value }; end }
127
+ end
108
128
 
129
+ end
109
130
  end
110
131
  end
@@ -8,20 +8,28 @@ module ActiveFacts
8
8
  module CQL
9
9
  grammar Concepts
10
10
  rule concept
11
- entity_type
12
- / data_type
11
+ value_type
12
+ / entity_type
13
13
  / named_fact_type
14
14
  / anonymous_fact_type
15
15
  end
16
16
 
17
17
  rule entity_type
18
- s name:id s
18
+ s term_definition_name
19
19
  sup:(basetype / subtype)
20
+ &{|e| input.context.entity_type(e[1].value); true }
21
+ mapping_pragmas
20
22
  ec:entity_conditions?
21
23
  ';' s
22
24
  {
25
+ def defined_type
26
+ [ :entity_type, sup.supers, sup.identifier, mapping_pragmas.value, (ec.empty? ? nil : ec.conditions) ]
27
+ end
28
+
23
29
  def value
24
- [ name.text_value, [ :entity_type, sup.supers, sup.identifier, ec.empty? ? nil : ec.conditions ] ]
30
+ [ term_definition_name.value,
31
+ defined_type
32
+ ]
25
33
  end
26
34
  }
27
35
  end
@@ -54,15 +62,15 @@ module ActiveFacts
54
62
  primary:id s
55
63
  alternate_supertypes:( ',' s !identified_by name:id s )*
56
64
  { def value
57
- [primary.text_value]+alternate_supertypes.elements.map{|sup| sup.name.text_value}
65
+ [primary.value]+alternate_supertypes.elements.map{|sup| sup.name.value}
58
66
  end
59
67
  }
60
68
  end
61
69
 
62
70
  rule identification
63
71
  # REVISIT: Consider distinguishing "-Id" from just "Id", and not prepending the entity type name if no "-"
64
- identified_by its s id s # Reference Mode
65
- { def value; {:mode => id.text_value }; end }
72
+ identified_by its s id value_type_parameters r:restriction? # Reference Mode; restriction may be needed for the ValueType
73
+ { def value; {:mode => id.value, :restriction => (r.text_value.empty? ? nil : r.ranges), :parameters => value_type_parameters.values }; end }
66
74
  /
67
75
  identified_by role_list
68
76
  { def value; {:roles => role_list.roles }; end }
@@ -93,15 +101,16 @@ module ActiveFacts
93
101
  l:lead_adj? tail:(s role_player_id)+ s t:trail_adj?
94
102
  {
95
103
  def value
96
- (l.empty? ? [] : [l.role_player_id.text_value]) +
97
- tail.elements.map{|e| e.role_player_id.text_value } +
98
- (t.empty? ? [] : [t.role_player_id.text_value])
104
+ (l.empty? ? [] : [l.role_player_id.value]) +
105
+ tail.elements.map{|e| e.role_player_id.value } +
106
+ (t.empty? ? [] : [t.role_player_id.value])
99
107
  end
100
108
  }
101
109
  end
102
110
 
103
111
  rule role_player_id
104
112
  !(role_list_sep / quantifier) id
113
+ { def value; id.value; end }
105
114
  end
106
115
 
107
116
  rule role_list_sep
@@ -113,6 +122,19 @@ module ActiveFacts
113
122
  '(' s '.' s mode_name:id s ')' s
114
123
  end
115
124
 
125
+ rule mapping_pragmas
126
+ '[' s h:mapping_pragma t:(s ',' s mapping_pragma)* s ']' s
127
+ { def value; [h.value] + t.elements.map{|e| e.mapping_pragma.value}; end }
128
+ /
129
+ ''
130
+ { def value; []; end }
131
+ end
132
+
133
+ rule mapping_pragma
134
+ (independent / separate / partitioned / personal / feminine / masculine)
135
+ { def value; text_value; end }
136
+ end
137
+
116
138
  rule entity_conditions
117
139
  (':' / where) s c:conditions?
118
140
  {
@@ -0,0 +1,34 @@
1
+ #
2
+ # ActiveFacts CQL Parser.
3
+ # Parse rules relating to definition context.
4
+ #
5
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
+ #
7
+ module ActiveFacts
8
+ module CQL
9
+ grammar Context
10
+ rule context
11
+ '('
12
+ w:who_says? s context_type discussion agreed:(',' a:as_agreed_by)? s
13
+ ')'
14
+ { def value; [ w.empty? ? nil : w.value, context_type.value, discussion.text_value, agreed.empty? ? [] : agreed.a.value]; end }
15
+ end
16
+
17
+ rule who_says
18
+ according_to people s ','
19
+ { def value; people.value; end }
20
+ end
21
+
22
+ rule context_type
23
+ because { def value; 'because'; end } /
24
+ as_opposed_to { def value; 'as_opposed_to'; end } /
25
+ so_that { def value; 'so_that'; end } /
26
+ to_avoid { def value; 'to_avoid'; end }
27
+ end
28
+
29
+ rule discussion
30
+ '(' discussion ')' / (!( [()] / ',' as_agreed_by) .)*
31
+ end
32
+ end
33
+ end
34
+ end
@@ -30,14 +30,14 @@ module ActiveFacts
30
30
  end
31
31
 
32
32
  rule sum
33
- t0:term s tail:( o:add_op s t1:term s )*
33
+ t0:product s tail:( op:add_op s t1:product s )*
34
34
  {
35
35
  def value
36
36
  return t0.value if tail.empty?
37
37
  [ :"+",
38
38
  *([t0.value] +
39
39
  tail.elements.map{|e|
40
- e.o.text_value == '-' ? [ :"-", e.t1.value ] : e.t1.value
40
+ e.op.text_value == '-' ? [ :"-", e.t1.value ] : e.t1.value
41
41
  }
42
42
  )
43
43
  ]
@@ -49,15 +49,15 @@ module ActiveFacts
49
49
  '+' / '-'
50
50
  end
51
51
 
52
- rule term
53
- f0:factor s tail:( o:mul_op s f1:factor s )*
52
+ rule product
53
+ f0:factor s tail:( op:mul_op s f1:factor s )*
54
54
  {
55
55
  def value
56
56
  return f0.value if tail.empty?
57
57
  [ :"*",
58
58
  *([f0.value] +
59
59
  tail.elements.map{|e|
60
- e.o.text_value != '*' ? [ :"-", e.f1.value ] : e.f1.value
60
+ e.op.text_value != '*' ? [ :"-", e.f1.value ] : e.f1.value
61
61
  }
62
62
  )
63
63
  ]
@@ -72,7 +72,7 @@ module ActiveFacts
72
72
  end
73
73
  }
74
74
  / derived_variable
75
- / '(' s sum s ')' s { def value; sum.value; end }
75
+ / !context '(' s sum s ')' s { def value; sum.value; end }
76
76
  end
77
77
 
78
78
  rule derived_variable
@@ -92,8 +92,8 @@ module ActiveFacts
92
92
  {
93
93
  def value
94
94
  # Variable names may consist of one or two words (optional adjective and a noun):
95
- r = [ :variable, id0.text_value ]
96
- r += [ o0.id1.text_value ] unless o0.empty?
95
+ r = [ :variable, id0.value ]
96
+ r += [ o0.id1.value ] unless o0.empty?
97
97
  r
98
98
  end
99
99
  }
@@ -103,7 +103,7 @@ module ActiveFacts
103
103
  '.' s func:id s param_list:( '(' s params:( p0:expression s tail:( ',' s p1:expression s )* )? ')' s )?
104
104
  {
105
105
  def value
106
- r = [ :"(", func.text_value ]
106
+ r = [ :"(", func.value ]
107
107
  return r if param_list.empty? || param_list.params.empty?
108
108
  r += [ param_list.params.p0.value ]
109
109
  param_list.params.tail.elements.each{|e|
@@ -8,12 +8,16 @@ module ActiveFacts
8
8
  module CQL
9
9
  grammar FactTypes
10
10
  rule named_fact_type
11
- s name:id ( s '=' s / written_as / s is s where )
11
+ s term_definition_name
12
+ ( written_as # REVISIT: What on earth was I thinking when I wrote this?
13
+ / s is s mapping_pragmas where # REVISIT: Need a place to put mapping pragmas like [independent]
14
+ )
15
+ &{|e| input.context.objectified_fact_type(e[1].value); true }
12
16
  anonymous_fact_type
13
17
  {
14
18
  def value
15
19
  f = anonymous_fact_type.value
16
- f[0] = name.text_value
20
+ f[0] = term_definition_name.value
17
21
  f
18
22
  end
19
23
  }
@@ -27,14 +31,9 @@ module ActiveFacts
27
31
  s ';' s
28
32
  {
29
33
  def value
30
- [
31
- nil, # Anonymous fact type
32
- [
33
- :fact_type,
34
- [ f0.body, *ftail.elements.map{|e| e.f1.body } ],
35
- !ctail.empty? ? ctail.c.condition_list : []
36
- ]
37
- ]
34
+ readings = [ f0.body, *ftail.elements.map{|e| e.f1.body } ]
35
+ conditions = !ctail.empty? ? ctail.c.condition_list : []
36
+ [ nil, [ :fact_type, readings, conditions ] ]
38
37
  end
39
38
  }
40
39
  end
@@ -71,6 +70,7 @@ module ActiveFacts
71
70
  end
72
71
 
73
72
  rule clause
73
+ # REVISIT: No context for comparisons, yet
74
74
  (comparison / fact_clause)
75
75
  {
76
76
  def clause
@@ -80,13 +80,14 @@ module ActiveFacts
80
80
  end
81
81
 
82
82
  rule fact_clause
83
- s q:qualifier? s reading s p:post_qualifiers? s
83
+ s q:qualifier? s reading s p:post_qualifiers? s c:context?
84
84
  {
85
85
  def body
86
86
  [ :fact_clause,
87
87
  (q.empty? ? [] : [ q.text_value ]) +
88
88
  (p.empty? ? [] : p.list),
89
- reading.value
89
+ reading.value,
90
+ c.empty? ? nil : c.value
90
91
  ]
91
92
  end
92
93
  }
@@ -110,8 +111,6 @@ module ActiveFacts
110
111
  end
111
112
 
112
113
  rule reading
113
- subtype_invocation
114
- /
115
114
  role+
116
115
  {
117
116
  def value
@@ -120,18 +119,6 @@ module ActiveFacts
120
119
  }
121
120
  end
122
121
 
123
- # REVISIT: This allows invocation from subtype to supertype. We need the reverse as well (Employee is a Manager).
124
- # Now that subtyping fact types have readings created during compilation, perhaps these custom rules can be removed?
125
- rule subtype_invocation
126
- (('some'/'that') S)? subtype:id s subtype_prefix (('some'/'that') S)? supertype:id
127
- {
128
- def value
129
- [{:subtype => subtype.text_value, :supertype => supertype.text_value }]
130
- # [subtype.text_value, "is", "a", "subtype", "of", supertype.text_value].map{|w| {:word => w}}
131
- end
132
- }
133
- end
134
-
135
122
  # This is the rule that causes most back-tracking. I think you can see why.
136
123
  # When we have an expression, we will come down here perhaps multiple times,
137
124
  # but find no way out as soon as we hit the trailing non_role.
@@ -141,7 +128,7 @@ module ActiveFacts
141
128
  player:role_word !'-' s?
142
129
  adj1:( '-' a:(a:role_word s)? )?
143
130
  func:function_call?
144
- role_name:( '(' s as S r:id s ')' s )?
131
+ role_id:(role_name / subscript )?
145
132
  lr:( literal / restriction )?
146
133
  !non_role
147
134
  {
@@ -150,13 +137,13 @@ module ActiveFacts
150
137
  quantifier = !q.empty? && q.value # "some" quantifier has nil value
151
138
 
152
139
  r[:quantifier] = quantifier if quantifier
153
- r[:leading_adjective] = adj0.a.text_value unless adj0.empty?
140
+ r[:leading_adjective] = adj0.a.value unless adj0.empty?
154
141
 
155
- r[:word] = player.text_value
142
+ r[:word] = player.value
156
143
 
157
- r[:trailing_adjective] = adj1.a.a.text_value unless adj1.empty?
144
+ r[:trailing_adjective] = adj1.a.a.value unless adj1.empty?
158
145
  r[:function] = func.value if !func.empty?
159
- r[:role_name] = role_name.r.text_value unless role_name.empty?
146
+ r[:role_name] = role_id.value unless role_id.empty?
160
147
  r[:restriction] = lr.ranges if !lr.empty? && lr.respond_to?(:ranges)
161
148
  r[:literal] = lr.value if !lr.empty? && lr.respond_to?(:value)
162
149
 
@@ -165,6 +152,16 @@ module ActiveFacts
165
152
  }
166
153
  end
167
154
 
155
+ rule role_name
156
+ '(' s as S r:id s ')' s
157
+ { def value; r.value; end }
158
+ end
159
+
160
+ rule subscript
161
+ '(' i:([1-9] [0-9]*) ')' s
162
+ { def value; i.text_value.to_i; end }
163
+ end
164
+
168
165
  rule non_role
169
166
  # Any of these is illegal in or following a reading:
170
167
  comparator
@@ -174,6 +171,7 @@ module ActiveFacts
174
171
 
175
172
  rule role_word
176
173
  !non_role_word id
174
+ { def value; id.value; end }
177
175
  end
178
176
 
179
177
  rule non_role_word
@@ -184,6 +182,7 @@ module ActiveFacts
184
182
  / or
185
183
  / quantifier
186
184
  / restriction
185
+ / but
187
186
  end
188
187
 
189
188
  end