Spectre 0.0.1

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 (38) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +23 -0
  3. data/README +20 -0
  4. data/Rakefile +112 -0
  5. data/lib/spectre/base.rb +44 -0
  6. data/lib/spectre/base/closure.rb +96 -0
  7. data/lib/spectre/base/directive.rb +148 -0
  8. data/lib/spectre/base/grammar.rb +269 -0
  9. data/lib/spectre/base/inputiterator.rb +276 -0
  10. data/lib/spectre/base/node.rb +393 -0
  11. data/lib/spectre/base/operators.rb +342 -0
  12. data/lib/spectre/base/parser.rb +110 -0
  13. data/lib/spectre/generic.rb +115 -0
  14. data/lib/spectre/generic/directives.rb +246 -0
  15. data/lib/spectre/generic/negations.rb +68 -0
  16. data/lib/spectre/generic/primitives.rb +172 -0
  17. data/lib/spectre/generic/semanticaction.rb +43 -0
  18. data/lib/spectre/string.rb +57 -0
  19. data/lib/spectre/string/additionals.rb +80 -0
  20. data/lib/spectre/string/directives.rb +51 -0
  21. data/lib/spectre/string/inputiterator.rb +57 -0
  22. data/lib/spectre/string/primitives.rb +400 -0
  23. data/test/base/closure_tests.rb +108 -0
  24. data/test/base/grammar_tests.rb +97 -0
  25. data/test/base/operator_tests.rb +335 -0
  26. data/test/base/semanticaction_tests.rb +53 -0
  27. data/test/generic/directive_tests.rb +224 -0
  28. data/test/generic/negation_tests.rb +146 -0
  29. data/test/generic/primitive_tests.rb +99 -0
  30. data/test/string/POD2Parser_tests.rb +93 -0
  31. data/test/string/additional_tests.rb +43 -0
  32. data/test/string/directive_tests.rb +32 -0
  33. data/test/string/primitive_tests.rb +173 -0
  34. data/test/tests.rb +33 -0
  35. data/test/tutorial/funnymath_tests.rb +57 -0
  36. data/test/tutorial/html_tests.rb +171 -0
  37. data/test/tutorial/skipping_tests.rb +60 -0
  38. metadata +109 -0
@@ -0,0 +1,68 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the generic Negation classes.
18
+ #
19
+
20
+ require 'spectre/base/parser'
21
+ require 'spectre/base/operators'
22
+
23
+ module Spectre
24
+
25
+ ##
26
+ # Keeps all the generic Negation classes.
27
+ #
28
+ module Negations
29
+
30
+ ##
31
+ # Negates a Parser that will consume a single token only.
32
+ #
33
+ class NegatedSingleTokenParser < Operators::Negation
34
+ include Parser
35
+
36
+ def scan iter
37
+ token = iter.get
38
+ ret = @node.left.parse iter
39
+ backtrack iter
40
+
41
+ if ret
42
+ nil
43
+ else
44
+ +iter
45
+ create_match iter, token
46
+ end
47
+ end
48
+ end
49
+
50
+ ##
51
+ # Negates a Paser that returns only 0 length matches.
52
+ #
53
+ class NegatedZeroTokenParser < Operators::Negation
54
+ include Parser
55
+
56
+ def scan iter
57
+ ret = @node.left.parse iter
58
+ backtrack iter
59
+
60
+ if ret then nil
61
+ else Match.new 0, iter.empty
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+
@@ -0,0 +1,172 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the generic Primitives.
18
+ #
19
+ # Registered shortcuts for generic primitive Parsers:
20
+ #
21
+ #
22
+ # RangeParser :range
23
+ # SequenceParser :seq
24
+ # NothingParser :nothing
25
+ # EOLParser :eol
26
+ # EOIParser :eoi
27
+ #
28
+ #
29
+ # See also ShortcutsMixin.
30
+ #
31
+
32
+ require 'spectre/base/parser'
33
+ require 'spectre/base/grammar'
34
+
35
+ module Spectre
36
+
37
+ ##
38
+ # Matches a range of tokens.
39
+ # Can be supplied with anything that implements the methods +#include?+,
40
+ # +#first+ and +#last+.
41
+ #
42
+ # Shortcut: +range+.
43
+ #
44
+ class RangeParser
45
+ include Parser
46
+
47
+ def initialize range
48
+ [:include?, :first, :last].each { |meth|
49
+ raise "#{range.inspect} does not respond to ##{meth}, which is required for RangeParser" unless
50
+ range.respond_to? meth
51
+ }
52
+
53
+ super()
54
+ @range = range
55
+ end
56
+
57
+ def negation; Negations::NegatedSingleTokenParser.new; end
58
+
59
+ def scan iter
60
+ return nil unless iter.valid?
61
+ token = +iter
62
+
63
+ if @range.include? token
64
+ create_match iter, token
65
+ else
66
+ nil
67
+ end
68
+ end
69
+
70
+ def inspect
71
+ "[range:#{@range.first}..#{@range.last}]"
72
+ end
73
+ end
74
+
75
+ ##
76
+ # Matches a sequence of tokens.
77
+ #
78
+ # Can be used on anything that is convertible to an array of tokens, i.e. the given
79
+ # object must either respond to +#split(Regexp)+ or +#to_a+.
80
+ #
81
+ # NOTE: It's negation is a zero token parser, i.e. +~seq([1,2,3])+ will only
82
+ # test if the input at that location contains the sequence and return a failure if so
83
+ # and a successful match of length 0 if not.
84
+ #
85
+ # Shortcut: +seq+.
86
+ #
87
+ class SequenceParser
88
+ include Parser
89
+
90
+ def initialize seq
91
+ raise "given object neither responds to #to_a nor #split, one of which is required for SequenceParser" unless
92
+ seq.respond_to? :to_a or seq.respond_to? :split
93
+
94
+ super()
95
+ @seq = seq
96
+ @seq = seq.respond_to?(:split) ? seq.split(//) : seq.to_a
97
+ end
98
+
99
+ def negation; Negations::NegatedZeroTokenParser.new; end
100
+
101
+ def scan iter
102
+ return nil unless iter.valid?
103
+ buf = iter.empty
104
+
105
+ @seq.each { |s|
106
+ token = iter.get
107
+ return nil if not iter.valid? or token != s
108
+ +iter
109
+ buf = iter.concat buf, token
110
+ }
111
+
112
+ create_match iter, buf
113
+ end
114
+
115
+ def inspect
116
+ "[seq:#{@seq.inject(''){ |memo,i| memo + i + ', ' }[0..-3] }]"
117
+ end
118
+ end
119
+
120
+ ##
121
+ # Matches nothing, i.e. it always fails.
122
+ # Shortcut: +nothing+.
123
+ #
124
+ class NothingParser
125
+ include Parser
126
+
127
+ def negation; Negations::NegatedZeroTokenParser.new; end
128
+
129
+ def scan iter
130
+ nil
131
+ end
132
+
133
+ def inspect
134
+ "[nothing]"
135
+ end
136
+ end
137
+
138
+ ##
139
+ # Matches the end of the input.
140
+ # Shortcut: +eoi+.
141
+ #
142
+ class EOIParser
143
+ include Parser
144
+
145
+ def negation; Negations::NegatedZeroTokenParser.new; end
146
+
147
+ def scan iter
148
+ iter.valid? ? nil : Match.new(0, iter.empty)
149
+ end
150
+
151
+ def inspect
152
+ "[EOI]"
153
+ end
154
+ end
155
+
156
+ ShortcutsMixin.register_shortcut( {
157
+ :range => RangeParser,
158
+ :seq => SequenceParser,
159
+ :nothing => NothingParser,
160
+ :eoi => EOIParser,
161
+ } )
162
+
163
+ end
164
+
165
+ ##
166
+ # Register Array as a POD with the RangeParser.
167
+ Spectre::register_POD(Array) { |arr| Spectre::RangeParser.new arr }
168
+
169
+ ##
170
+ # Register Range as a POD with the RangeParser.
171
+ Spectre::register_POD(Range) { |arr| Spectre::RangeParser.new arr }
172
+
@@ -0,0 +1,43 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the pre-defined semantic action classes.
18
+ #
19
+
20
+ module Spectre
21
+
22
+ ##
23
+ # This semantic action will be instantiated everytime a symbol is given to
24
+ # +Parser#[]+.
25
+ # It stores the value it receives inside the closure.
26
+ #
27
+ class ClosureAction
28
+
29
+ ##
30
+ # +sym+ is the Symbol under which the parsed value will be stored in the Closure.
31
+ #
32
+ def initialize sym
33
+ @sym = sym
34
+ end
35
+
36
+ def call match, closure
37
+ raise "no closure set for ClosureAction" unless closure
38
+ closure[@sym] = match.value
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,57 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the Standard Parsers and InputIterators for String parsing.
18
+ # See Spectre::StringParsing.
19
+ #
20
+
21
+ require 'spectre/base'
22
+ require 'spectre/generic'
23
+ require 'spectre/string/inputiterator'
24
+ require 'spectre/string/primitives'
25
+ require 'spectre/string/additionals'
26
+ require 'spectre/string/directives'
27
+
28
+ module Spectre
29
+
30
+ module StringParsing
31
+
32
+ include Spectre
33
+
34
+ ##
35
+ # Shortcut that parses the +string+ using the +parser+ and a StringInputIterator.
36
+ # +pre_skip+ will be passed on to +Node#parse+.
37
+ # If you mix the StringParsing module into your class, it will gain this method.
38
+ #
39
+ def parse string, parser, pre_skip = true
40
+ parser.to_p.parse StringInputIterator.new(string), pre_skip
41
+ end
42
+
43
+ class << self
44
+ ##
45
+ # Shortcut that parses the +string+ using the +parser+ and a StringInputIterator.
46
+ # +pre_skip+ will be passed on to +Node#parse+.
47
+ # If you mix the StringParsing module into your class, it will gain this method.
48
+ #
49
+ def parse string, parser, pre_skip = true
50
+ parser.to_p.parse StringInputIterator.new(string), pre_skip
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
@@ -0,0 +1,80 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the Parsers for StringParsing that are used less commonly and are
18
+ # more complex than the primitives.
19
+ # Registered shortcuts for additional String Parsers:
20
+ #
21
+ # RegExpParser :rex
22
+ #
23
+ # See also ShortcutsMixin.
24
+ #
25
+
26
+ require 'spectre/base/parser'
27
+ require 'spectre/base/grammar'
28
+
29
+ module Spectre
30
+
31
+ module StringParsing
32
+
33
+ ##
34
+ # Matches a regular expression.
35
+ # Naturally this Parser is an implicit lexeme, i.e. it will ignore any skippers set
36
+ # on the InputIterator.
37
+ #
38
+ # NOTE: In order to calculate the Match, the regular expression will be applied to
39
+ # the whole rest of the InputIterator.
40
+ #
41
+ # Shortcut: +rex+.
42
+ #
43
+ class RegExpParser
44
+ include Parser
45
+
46
+ def initialize rex
47
+ super()
48
+ @rex = rex
49
+ end
50
+
51
+ def scan iter
52
+ m = @rex.match iter.rest
53
+
54
+ if m and m.pre_match.empty?
55
+ backtrack iter
56
+ data = nil
57
+ iter.ignore_skipper { |i| data = i + m[0].length }
58
+ create_match iter, data
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def inspect
65
+ "[regexp:#{@rex.inspect}]"
66
+ end
67
+ end
68
+
69
+ ShortcutsMixin.register_shortcut :rex => RegExpParser
70
+
71
+ end
72
+
73
+ end
74
+
75
+ ##
76
+ # Register regular expressions as a POD with the RegExpParser.
77
+ Spectre::register_POD(Regexp) do |rex|
78
+ Spectre::StringParsing::RegExpParser.new rex
79
+ end
80
+
@@ -0,0 +1,51 @@
1
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
2
+ # which can be found at http://spirit.sourceforge.net/.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://spectre.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
10
+ # License:: Boost Software License 1.0
11
+ # For further information regarding this license, you can go to
12
+ # http://www.boost.org/LICENSE_1_0.txt
13
+ # or read the file LICENSE distributed with this software.
14
+ # Homepage:: http://spectre.rubyforge.org/
15
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
16
+ #
17
+ # Keeps the Standard Directives for String parsing.
18
+ # Registered shortcuts for standard String Directives:
19
+ #
20
+ # CharParser :char
21
+ #
22
+ # See also ShortcutsMixin.
23
+ #
24
+
25
+ require 'spectre/base/directive'
26
+ require 'spectre/base/grammar'
27
+ require 'spectre/generic/directives'
28
+
29
+ module Spectre
30
+
31
+ module StringParsing
32
+
33
+ ##
34
+ # Converts the input to lower-case.
35
+ #
36
+ # Shortcut: +lower_d+
37
+ #
38
+ class LowerDirective < Directive
39
+ transformation! lambda { |token,is| token.downcase }
40
+
41
+ def inspect
42
+ "[lower_d:#{@left.inspect}]"
43
+ end
44
+ end
45
+
46
+ ShortcutsMixin.register_shortcut :lower_d => LowerDirective
47
+
48
+ end
49
+
50
+ end
51
+