activefacts 0.7.3 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
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