citrus 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/citrus.gemspec +2 -2
- data/examples/calc.citrus +4 -20
- data/examples/calc.rb +4 -10
- data/examples/calc_sugar.rb +4 -10
- data/lib/citrus.rb +48 -43
- data/lib/citrus/debug.rb +4 -2
- data/lib/citrus/file.rb +5 -16
- data/test/calc_file_test.rb +1 -1
- data/test/calc_sugar_test.rb +1 -1
- data/test/calc_test.rb +1 -1
- data/test/helper.rb +1 -1
- data/test/super_test.rb +2 -2
- metadata +4 -4
data/citrus.gemspec
CHANGED
data/examples/calc.citrus
CHANGED
@@ -3,11 +3,7 @@
|
|
3
3
|
# ignoring whitespace.
|
4
4
|
grammar Calc
|
5
5
|
rule term
|
6
|
-
|
7
|
-
def value
|
8
|
-
first.value
|
9
|
-
end
|
10
|
-
}
|
6
|
+
additive | factor
|
11
7
|
end
|
12
8
|
|
13
9
|
rule additive
|
@@ -19,11 +15,7 @@ grammar Calc
|
|
19
15
|
end
|
20
16
|
|
21
17
|
rule factor
|
22
|
-
|
23
|
-
def value
|
24
|
-
first.value
|
25
|
-
end
|
26
|
-
}
|
18
|
+
multiplicative | primary
|
27
19
|
end
|
28
20
|
|
29
21
|
rule multiplicative
|
@@ -35,11 +27,7 @@ grammar Calc
|
|
35
27
|
end
|
36
28
|
|
37
29
|
rule primary
|
38
|
-
|
39
|
-
def value
|
40
|
-
first.value
|
41
|
-
end
|
42
|
-
}
|
30
|
+
term_paren | number
|
43
31
|
end
|
44
32
|
|
45
33
|
rule term_paren
|
@@ -67,11 +55,7 @@ grammar Calc
|
|
67
55
|
end
|
68
56
|
|
69
57
|
rule number
|
70
|
-
|
71
|
-
def value
|
72
|
-
first.value
|
73
|
-
end
|
74
|
-
}
|
58
|
+
float | integer
|
75
59
|
end
|
76
60
|
|
77
61
|
rule float
|
data/examples/calc.rb
CHANGED
@@ -6,14 +6,8 @@ require 'citrus'
|
|
6
6
|
module Calc
|
7
7
|
include Citrus::Grammar
|
8
8
|
|
9
|
-
module FirstValue
|
10
|
-
def value
|
11
|
-
first.value
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
9
|
rule :term do
|
16
|
-
|
10
|
+
any(:additive, :factor)
|
17
11
|
end
|
18
12
|
|
19
13
|
rule :additive do
|
@@ -25,7 +19,7 @@ module Calc
|
|
25
19
|
end
|
26
20
|
|
27
21
|
rule :factor do
|
28
|
-
|
22
|
+
any(:multiplicative, :primary)
|
29
23
|
end
|
30
24
|
|
31
25
|
rule :multiplicative do
|
@@ -37,7 +31,7 @@ module Calc
|
|
37
31
|
end
|
38
32
|
|
39
33
|
rule :primary do
|
40
|
-
|
34
|
+
any(:term_paren, :number)
|
41
35
|
end
|
42
36
|
|
43
37
|
rule :term_paren do
|
@@ -65,7 +59,7 @@ module Calc
|
|
65
59
|
end
|
66
60
|
|
67
61
|
rule :number do
|
68
|
-
|
62
|
+
any(:float, :integer)
|
69
63
|
end
|
70
64
|
|
71
65
|
rule :float do
|
data/examples/calc_sugar.rb
CHANGED
@@ -4,14 +4,8 @@ require 'citrus/sugar'
|
|
4
4
|
# non-negative numbers (integers and floats), respecting operator precedence and
|
5
5
|
# ignoring whitespace.
|
6
6
|
Calc = Citrus::Grammar.new {
|
7
|
-
module FirstValue
|
8
|
-
def value
|
9
|
-
first.value
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
7
|
rule term do
|
14
|
-
|
8
|
+
any(additive, factor)
|
15
9
|
end
|
16
10
|
|
17
11
|
rule additive do
|
@@ -23,7 +17,7 @@ Calc = Citrus::Grammar.new {
|
|
23
17
|
end
|
24
18
|
|
25
19
|
rule factor do
|
26
|
-
|
20
|
+
any(multiplicative, primary)
|
27
21
|
end
|
28
22
|
|
29
23
|
rule multiplicative do
|
@@ -35,7 +29,7 @@ Calc = Citrus::Grammar.new {
|
|
35
29
|
end
|
36
30
|
|
37
31
|
rule primary do
|
38
|
-
|
32
|
+
any(term_paren, number)
|
39
33
|
end
|
40
34
|
|
41
35
|
rule term_paren do
|
@@ -63,7 +57,7 @@ Calc = Citrus::Grammar.new {
|
|
63
57
|
end
|
64
58
|
|
65
59
|
rule number do
|
66
|
-
|
60
|
+
any(float, integer)
|
67
61
|
end
|
68
62
|
|
69
63
|
rule float do
|
data/lib/citrus.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# http://mjijackson.com/citrus
|
6
6
|
module Citrus
|
7
|
-
VERSION = [1,
|
7
|
+
VERSION = [1, 3, 0]
|
8
8
|
|
9
9
|
Infinity = 1.0 / 0
|
10
10
|
|
@@ -419,13 +419,13 @@ module Citrus
|
|
419
419
|
private
|
420
420
|
|
421
421
|
def extend_match(match)
|
422
|
-
match.ext
|
422
|
+
match.extend(ext) if ext
|
423
423
|
end
|
424
424
|
|
425
425
|
def create_match(data, offset)
|
426
426
|
match = Match.new(data, offset)
|
427
427
|
extend_match(match)
|
428
|
-
match.name
|
428
|
+
match.names << name if name
|
429
429
|
match
|
430
430
|
end
|
431
431
|
end
|
@@ -437,13 +437,13 @@ module Citrus
|
|
437
437
|
module Proxy
|
438
438
|
include Rule
|
439
439
|
|
440
|
-
def initialize(
|
441
|
-
self.rule_name =
|
440
|
+
def initialize(rule_name='<proxy>')
|
441
|
+
self.rule_name = rule_name
|
442
442
|
end
|
443
443
|
|
444
444
|
# Sets the name of the rule this rule is proxy for.
|
445
|
-
def rule_name=(
|
446
|
-
@rule_name =
|
445
|
+
def rule_name=(rule_name)
|
446
|
+
@rule_name = rule_name.to_sym
|
447
447
|
end
|
448
448
|
|
449
449
|
# The name of this proxy's rule.
|
@@ -460,8 +460,8 @@ module Citrus
|
|
460
460
|
m = input.match(rule, offset)
|
461
461
|
if m
|
462
462
|
extend_match(m)
|
463
|
-
#
|
464
|
-
m.
|
463
|
+
# This proxy's name should be added to the names of the match.
|
464
|
+
m.names << name if name
|
465
465
|
m
|
466
466
|
end
|
467
467
|
end
|
@@ -675,13 +675,18 @@ module Citrus
|
|
675
675
|
class Label
|
676
676
|
include Predicate
|
677
677
|
|
678
|
-
def initialize(
|
679
|
-
@label = label.to_sym
|
678
|
+
def initialize(label_name='<label>', rule='')
|
680
679
|
super(rule)
|
680
|
+
self.label_name = label_name
|
681
681
|
end
|
682
682
|
|
683
|
-
#
|
684
|
-
|
683
|
+
# Sets the name of this label.
|
684
|
+
def label_name=(label_name)
|
685
|
+
@label_name = label_name.to_sym
|
686
|
+
end
|
687
|
+
|
688
|
+
# The name this rule adds to all its matches.
|
689
|
+
attr_reader :label_name
|
685
690
|
|
686
691
|
# Returns the Match for this rule on +input+ at the given +offset+, +nil+ if
|
687
692
|
# no match can be made. When a Label makes a match, it re-names the match to
|
@@ -690,14 +695,15 @@ module Citrus
|
|
690
695
|
m = rule.match(input, offset)
|
691
696
|
if m
|
692
697
|
extend_match(m)
|
693
|
-
|
698
|
+
# This label's name should be added to the names of the match.
|
699
|
+
m.names << label_name
|
694
700
|
m
|
695
701
|
end
|
696
702
|
end
|
697
703
|
|
698
704
|
# Returns the Citrus notation of this rule as a string.
|
699
705
|
def to_s
|
700
|
-
|
706
|
+
label_name.to_s + ':' + rule.embed
|
701
707
|
end
|
702
708
|
end
|
703
709
|
|
@@ -794,7 +800,12 @@ module Citrus
|
|
794
800
|
def match(input, offset=0)
|
795
801
|
rules.each do |rule|
|
796
802
|
m = input.match(rule, offset)
|
797
|
-
|
803
|
+
if m
|
804
|
+
extend_match(m)
|
805
|
+
# This choice's name should be added to the names of the match.
|
806
|
+
m.names << name if name
|
807
|
+
return m
|
808
|
+
end
|
798
809
|
end
|
799
810
|
nil
|
800
811
|
end
|
@@ -851,18 +862,26 @@ module Citrus
|
|
851
862
|
@offset = offset
|
852
863
|
end
|
853
864
|
|
854
|
-
# The name by which this match can be accessed from a parent match. This
|
855
|
-
# will be the name of the rule that generated the match in most cases.
|
856
|
-
# However, if the match is the result of a Label this will be the value of
|
857
|
-
# the label.
|
858
|
-
attr_accessor :name
|
859
|
-
|
860
|
-
# A module that will be used to extend this match.
|
861
|
-
attr_accessor :ext
|
862
|
-
|
863
865
|
# The offset in the input at which this match occurred.
|
864
866
|
attr_reader :offset
|
865
867
|
|
868
|
+
# An array of all names of this match. A name is added to a match object
|
869
|
+
# for each rule that returns that object when matching. These names can then
|
870
|
+
# be used to determine which rules were satisfied by a given match.
|
871
|
+
def names
|
872
|
+
@names ||= []
|
873
|
+
end
|
874
|
+
|
875
|
+
# The name of the lowest level rule that originally created this match.
|
876
|
+
def name
|
877
|
+
names.first
|
878
|
+
end
|
879
|
+
|
880
|
+
# Returns +true+ if this match has the given +name+.
|
881
|
+
def has_name?(name)
|
882
|
+
names.include?(name)
|
883
|
+
end
|
884
|
+
|
866
885
|
# An array of all sub-matches of this match.
|
867
886
|
def matches
|
868
887
|
@matches ||= []
|
@@ -897,7 +916,7 @@ module Citrus
|
|
897
916
|
# match.
|
898
917
|
def find(name, deep=true)
|
899
918
|
sym = name.to_sym
|
900
|
-
ms = matches.select {|m|
|
919
|
+
ms = matches.select {|m| m.has_name?(sym) }
|
901
920
|
ms.concat(matches.map {|m| m.find(name, deep) }.flatten) if deep
|
902
921
|
ms
|
903
922
|
end
|
@@ -925,23 +944,9 @@ module Citrus
|
|
925
944
|
# Uses #match to allow sub-matches of this match to be called by name as
|
926
945
|
# instance methods.
|
927
946
|
def method_missing(sym, *args)
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
redefine_method_missing!
|
932
|
-
__send__(sym, *args)
|
933
|
-
end
|
934
|
-
|
935
|
-
private
|
936
|
-
|
937
|
-
def redefine_method_missing! # :nodoc:
|
938
|
-
instance_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
939
|
-
def method_missing(sym, *args)
|
940
|
-
m = first(sym)
|
941
|
-
return m if m
|
942
|
-
raise 'No match named "%s" in %s (%s)' % [sym, self, name]
|
943
|
-
end
|
944
|
-
RUBY
|
947
|
+
m = first(sym)
|
948
|
+
return m if m
|
949
|
+
raise 'No match named "%s" in %s (%s)' % [sym, self, name]
|
945
950
|
end
|
946
951
|
end
|
947
952
|
end
|
data/lib/citrus/debug.rb
CHANGED
@@ -13,10 +13,12 @@ module Citrus
|
|
13
13
|
xml.instruct!
|
14
14
|
end
|
15
15
|
|
16
|
+
attrs = { "names" => names.join(','), "text" => text, "offset" => offset }
|
17
|
+
|
16
18
|
if matches.empty?
|
17
|
-
xml.match(
|
19
|
+
xml.match(attrs)
|
18
20
|
else
|
19
|
-
xml.match(
|
21
|
+
xml.match(attrs) do
|
20
22
|
matches.each {|m| m.to_markup(xml) }
|
21
23
|
end
|
22
24
|
end
|
data/lib/citrus/file.rb
CHANGED
@@ -74,7 +74,7 @@ module Citrus
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def values
|
77
|
-
choices.map {|
|
77
|
+
choices.map {|c| c.value }
|
78
78
|
end
|
79
79
|
|
80
80
|
def value
|
@@ -137,11 +137,7 @@ module Citrus
|
|
137
137
|
end
|
138
138
|
|
139
139
|
rule :primary do
|
140
|
-
any(:super, :alias, :rule_body_paren, :terminal)
|
141
|
-
def value
|
142
|
-
first.value
|
143
|
-
end
|
144
|
-
}
|
140
|
+
any(:super, :alias, :rule_body_paren, :terminal)
|
145
141
|
end
|
146
142
|
|
147
143
|
rule :rule_body_paren do
|
@@ -205,7 +201,7 @@ module Citrus
|
|
205
201
|
rule :terminal do
|
206
202
|
any(:quoted_string, :character_class, :anything_symbol, :regular_expression) {
|
207
203
|
def value
|
208
|
-
Rule.create(
|
204
|
+
Rule.create(super)
|
209
205
|
end
|
210
206
|
}
|
211
207
|
end
|
@@ -243,11 +239,7 @@ module Citrus
|
|
243
239
|
end
|
244
240
|
|
245
241
|
rule :qualifier do
|
246
|
-
any(:and, :not, :label)
|
247
|
-
def wrap(rule)
|
248
|
-
first.wrap(rule)
|
249
|
-
end
|
250
|
-
}
|
242
|
+
any(:and, :not, :label)
|
251
243
|
end
|
252
244
|
|
253
245
|
rule :and do
|
@@ -281,7 +273,7 @@ module Citrus
|
|
281
273
|
rule :extension do
|
282
274
|
any(:tag, :block) {
|
283
275
|
def wrap(rule)
|
284
|
-
rule.ext =
|
276
|
+
rule.ext = value
|
285
277
|
rule
|
286
278
|
end
|
287
279
|
}
|
@@ -305,9 +297,6 @@ module Citrus
|
|
305
297
|
|
306
298
|
rule :quantifier do
|
307
299
|
any(:question, :plus, :repeat) {
|
308
|
-
def min; first.min end
|
309
|
-
def max; first.max end
|
310
|
-
|
311
300
|
def wrap(rule)
|
312
301
|
Repeat.new(min, max, rule)
|
313
302
|
end
|
data/test/calc_file_test.rb
CHANGED
data/test/calc_sugar_test.rb
CHANGED
data/test/calc_test.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/super_test.rb
CHANGED
@@ -51,11 +51,11 @@ class SuperTest < Test::Unit::TestCase
|
|
51
51
|
|
52
52
|
match = grammar2.parse('a')
|
53
53
|
assert(match)
|
54
|
-
assert_equal(:a, match.
|
54
|
+
assert_equal(:a, match.name)
|
55
55
|
|
56
56
|
match = grammar2.parse('b')
|
57
57
|
assert(match)
|
58
|
-
assert_equal(:b, match.
|
58
|
+
assert_equal(:b, match.name)
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_to_s
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 1.
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 1.3.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Michael Jackson
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-21 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|