Spectre 0.0.1

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