walrus 0.2 → 0.3

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 (93) hide show
  1. data/bin/walrus +19 -12
  2. data/lib/walrus.rb +27 -70
  3. data/lib/walrus/additions/string.rb +21 -35
  4. data/lib/walrus/compile_error.rb +19 -16
  5. data/lib/walrus/compiler.rb +66 -55
  6. data/lib/walrus/contrib/spec/walruscloth_spec.rb +21 -17
  7. data/lib/walrus/contrib/walruscloth.rb +19 -11
  8. data/lib/walrus/document.rb +41 -33
  9. data/lib/walrus/grammar.rb +474 -162
  10. data/lib/walrus/grammar/assignment_expression.rb +33 -0
  11. data/lib/walrus/grammar/block_directive.rb +37 -0
  12. data/lib/walrus/grammar/comment.rb +33 -0
  13. data/lib/walrus/grammar/def_directive.rb +80 -0
  14. data/lib/walrus/grammar/echo_directive.rb +56 -0
  15. data/lib/walrus/grammar/escape_sequence.rb +33 -0
  16. data/lib/walrus/grammar/import_directive.rb +54 -0
  17. data/lib/walrus/grammar/include_directive.rb +36 -0
  18. data/lib/walrus/grammar/instance_variable.rb +33 -0
  19. data/lib/walrus/grammar/literal.rb +33 -0
  20. data/lib/walrus/grammar/message_expression.rb +34 -0
  21. data/lib/walrus/grammar/multiline_comment.rb +70 -0
  22. data/lib/walrus/grammar/placeholder.rb +47 -0
  23. data/lib/walrus/grammar/raw_directive.rb +50 -0
  24. data/lib/walrus/grammar/raw_text.rb +56 -0
  25. data/lib/walrus/grammar/ruby_directive.rb +41 -0
  26. data/lib/walrus/grammar/ruby_expression.rb +42 -0
  27. data/lib/walrus/grammar/set_directive.rb +34 -0
  28. data/lib/walrus/grammar/silent_directive.rb +51 -0
  29. data/lib/walrus/grammar/slurp_directive.rb +36 -0
  30. data/lib/walrus/grammar/super_directive.rb +34 -0
  31. data/lib/walrus/parser.rb +26 -408
  32. data/lib/walrus/runner.rb +37 -20
  33. data/lib/walrus/template.rb +34 -25
  34. data/lib/walrus/version.rb +24 -1
  35. metadata +57 -71
  36. data/ext/extconf.rb +0 -16
  37. data/ext/jindex.c +0 -92
  38. data/lib/walrus/diff.rb +0 -95
  39. data/lib/walrus/grammar/additions/proc.rb +0 -26
  40. data/lib/walrus/grammar/additions/regexp.rb +0 -27
  41. data/lib/walrus/grammar/additions/string.rb +0 -58
  42. data/lib/walrus/grammar/additions/symbol.rb +0 -49
  43. data/lib/walrus/grammar/and_predicate.rb +0 -46
  44. data/lib/walrus/grammar/array_result.rb +0 -25
  45. data/lib/walrus/grammar/continuation_wrapper_exception.rb +0 -34
  46. data/lib/walrus/grammar/left_recursion_exception.rb +0 -33
  47. data/lib/walrus/grammar/location_tracking.rb +0 -115
  48. data/lib/walrus/grammar/match_data_wrapper.rb +0 -71
  49. data/lib/walrus/grammar/memoizing.rb +0 -47
  50. data/lib/walrus/grammar/memoizing_cache.rb +0 -103
  51. data/lib/walrus/grammar/node.rb +0 -66
  52. data/lib/walrus/grammar/not_predicate.rb +0 -46
  53. data/lib/walrus/grammar/parse_error.rb +0 -45
  54. data/lib/walrus/grammar/parser_state.rb +0 -187
  55. data/lib/walrus/grammar/parslet.rb +0 -34
  56. data/lib/walrus/grammar/parslet_choice.rb +0 -128
  57. data/lib/walrus/grammar/parslet_combination.rb +0 -32
  58. data/lib/walrus/grammar/parslet_combining.rb +0 -160
  59. data/lib/walrus/grammar/parslet_merge.rb +0 -94
  60. data/lib/walrus/grammar/parslet_omission.rb +0 -63
  61. data/lib/walrus/grammar/parslet_repetition.rb +0 -106
  62. data/lib/walrus/grammar/parslet_repetition_default.rb +0 -64
  63. data/lib/walrus/grammar/parslet_sequence.rb +0 -214
  64. data/lib/walrus/grammar/predicate.rb +0 -63
  65. data/lib/walrus/grammar/proc_parslet.rb +0 -58
  66. data/lib/walrus/grammar/regexp_parslet.rb +0 -79
  67. data/lib/walrus/grammar/skipped_substring_exception.rb +0 -42
  68. data/lib/walrus/grammar/string_enumerator.rb +0 -53
  69. data/lib/walrus/grammar/string_parslet.rb +0 -81
  70. data/lib/walrus/grammar/string_result.rb +0 -30
  71. data/lib/walrus/grammar/symbol_parslet.rb +0 -69
  72. data/lib/walrus/no_parameter_marker.rb +0 -25
  73. data/lib/walrus/walrus_grammar/assignment_expression.rb +0 -30
  74. data/lib/walrus/walrus_grammar/block_directive.rb +0 -34
  75. data/lib/walrus/walrus_grammar/comment.rb +0 -30
  76. data/lib/walrus/walrus_grammar/def_directive.rb +0 -72
  77. data/lib/walrus/walrus_grammar/echo_directive.rb +0 -50
  78. data/lib/walrus/walrus_grammar/escape_sequence.rb +0 -30
  79. data/lib/walrus/walrus_grammar/import_directive.rb +0 -50
  80. data/lib/walrus/walrus_grammar/include_directive.rb +0 -33
  81. data/lib/walrus/walrus_grammar/instance_variable.rb +0 -30
  82. data/lib/walrus/walrus_grammar/literal.rb +0 -30
  83. data/lib/walrus/walrus_grammar/message_expression.rb +0 -31
  84. data/lib/walrus/walrus_grammar/multiline_comment.rb +0 -60
  85. data/lib/walrus/walrus_grammar/placeholder.rb +0 -46
  86. data/lib/walrus/walrus_grammar/raw_directive.rb +0 -48
  87. data/lib/walrus/walrus_grammar/raw_text.rb +0 -51
  88. data/lib/walrus/walrus_grammar/ruby_directive.rb +0 -35
  89. data/lib/walrus/walrus_grammar/ruby_expression.rb +0 -37
  90. data/lib/walrus/walrus_grammar/set_directive.rb +0 -30
  91. data/lib/walrus/walrus_grammar/silent_directive.rb +0 -50
  92. data/lib/walrus/walrus_grammar/slurp_directive.rb +0 -31
  93. data/lib/walrus/walrus_grammar/super_directive.rb +0 -33
@@ -1,63 +0,0 @@
1
- # Copyright 2007 Wincent Colaiuta
2
- # This program is free software: you can redistribute it and/or modify
3
- # it under the terms of the GNU General Public License as published by
4
- # the Free Software Foundation, either version 3 of the License, or
5
- # (at your option) any later version.
6
- #
7
- # This program is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- # GNU General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU General Public License
13
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
-
15
- require 'walrus'
16
-
17
- module Walrus
18
- class Grammar
19
-
20
- class ParsletOmission < ParsletCombination
21
-
22
- attr_reader :hash
23
-
24
- # Raises an ArgumentError if parseable is nil.
25
- def initialize(parseable)
26
- raise ArgumentError if parseable.nil?
27
- @parseable = parseable
28
- @hash = @parseable.hash + 46 # fixed offset to avoid unwanted collisions with similar classes
29
- end
30
-
31
- def parse(string, options = {})
32
- raise ArgumentError if string.nil?
33
- substring = StringResult.new
34
- substring.start = [options[:line_start], options[:column_start]]
35
- substring.end = [options[:line_start], options[:column_start]]
36
-
37
- # possibly should catch these here as well
38
- #catch :NotPredicateSuccess do
39
- #catch :AndPredicateSuccess do
40
- # one of the fundamental problems is that if a parslet throws such a symbol any info about already skipped material is lost (because the symbols contain nothing)
41
- # this may be one reason to change these to exceptions...
42
- catch :ZeroWidthParseSuccess do
43
- substring = @parseable.memoizing_parse(string, options)
44
- end
45
-
46
- # not enough to just return a ZeroWidthParseSuccess here; that could cause higher levels to stop parsing and in any case there'd be no clean way to embed the scanned substring in the symbol
47
- raise SkippedSubstringException.new(substring,
48
- :line_start => options[:line_start], :column_start => options[:column_start],
49
- :line_end => substring.line_end, :column_end => substring.column_end)
50
- end
51
-
52
- def eql?(other)
53
- other.instance_of? ParsletOmission and other.parseable.eql? @parseable
54
- end
55
-
56
- protected
57
-
58
- # For determining equality.
59
- attr_reader :parseable
60
-
61
- end # class ParsletOmission
62
- end # class Grammar
63
- end # module Walrus
@@ -1,106 +0,0 @@
1
- # Copyright 2007 Wincent Colaiuta
2
- # This program is free software: you can redistribute it and/or modify
3
- # it under the terms of the GNU General Public License as published by
4
- # the Free Software Foundation, either version 3 of the License, or
5
- # (at your option) any later version.
6
- #
7
- # This program is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- # GNU General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU General Public License
13
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
-
15
- require 'walrus'
16
-
17
- module Walrus
18
- class Grammar
19
-
20
- class ParsletRepetition < ParsletCombination
21
-
22
- attr_reader :hash
23
-
24
- # Raises an ArgumentError if parseable or min is nil.
25
- def initialize(parseable, min, max = nil)
26
- raise ArgumentError if parseable.nil?
27
- raise ArgumentError if min.nil?
28
- @parseable = parseable
29
- self.min = min
30
- self.max = max
31
- end
32
-
33
- def parse(string, options = {})
34
- raise ArgumentError if string.nil?
35
- state = ParserState.new(string, options)
36
- catch :ZeroWidthParseSuccess do # a zero-width match is grounds for immediate abort
37
- while @max.nil? or state.length < @max # try forever if max is nil; otherwise keep trying while match count < max
38
- begin
39
- parsed = @parseable.memoizing_parse(state.remainder, state.options)
40
- state.parsed(parsed)
41
- rescue SkippedSubstringException => e
42
- state.skipped(e)
43
- rescue ParseError => e # failed, will try to skip; save original error in case skipping fails
44
- if options.has_key?(:skipping_override)
45
- skipping_parslet = options[:skipping_override]
46
- elsif options.has_key?(:skipping)
47
- skipping_parslet = options[:skipping]
48
- else
49
- skipping_parslet = nil
50
- end
51
- break if skipping_parslet.nil?
52
- begin
53
- parsed = skipping_parslet.memoizing_parse(state.remainder, state.options) # guard against self references (possible infinite recursion) here?
54
- state.skipped(parsed)
55
- redo # skipping succeeded, try to redo
56
- rescue ParseError
57
- break # skipping didn't help either, give up
58
- end
59
- end
60
- end
61
- end
62
-
63
- # now assess whether our tries met the requirements
64
- if state.length == 0 and @min == 0 # success (special case)
65
- throw :ZeroWidthParseSuccess
66
- elsif state.length < @min # matches < min (failure)
67
- raise ParseError.new('required %d matches but obtained %d while parsing "%s"' % [@min, state.length, string],
68
- :line_end => state.options[:line_end], :column_end => state.options[:column_end])
69
- else # success (general case)
70
- state.results # returns multiple matches as an array, single matches as a single object
71
- end
72
-
73
- end
74
-
75
- def eql?(other)
76
- other.instance_of? ParsletRepetition and @min == other.min and @max == other.max and @parseable.eql? other.parseable
77
- end
78
-
79
- protected
80
-
81
- # For determining equality.
82
- attr_reader :parseable, :min, :max
83
-
84
- private
85
-
86
- def hash_offset
87
- 87
88
- end
89
-
90
- def update_hash
91
- @hash = @min.hash + @max.hash + @parseable.hash + hash_offset # fixed offset to minimize risk of collisions
92
- end
93
-
94
- def min=(min)
95
- @min = (min.clone rescue min)
96
- update_hash
97
- end
98
-
99
- def max=(max)
100
- @max = (max.clone rescue max)
101
- update_hash
102
- end
103
-
104
- end # class ParsletRepetition
105
- end # class Grammar
106
- end # module Walrus
@@ -1,64 +0,0 @@
1
- # Copyright 2007 Wincent Colaiuta
2
- # This program is free software: you can redistribute it and/or modify
3
- # it under the terms of the GNU General Public License as published by
4
- # the Free Software Foundation, either version 3 of the License, or
5
- # (at your option) any later version.
6
- #
7
- # This program is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- # GNU General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU General Public License
13
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
-
15
- require 'walrus'
16
-
17
- module Walrus
18
- class Grammar
19
-
20
- # ParsletRepetitionDefault is a subclass that modifies the behaviour of its parent, ParsletRepetition, in a very small way. Namely, if the outcome of parsing is a ZeroWidthParse success then it is caught and the default value (defined at initialization time) is returned instead.
21
- class ParsletRepetitionDefault < ParsletRepetition
22
-
23
- # Possible re-factoring to consider for the future: roll the functionality of this class in to ParsletRepetition itself.
24
- # Benefit of keeping it separate is that the ParsletRepetition itself is kept simple.
25
- def initialize(parseable, min, max = nil, default = nil)
26
- super(parseable, min, max)
27
- self.default = default
28
- end
29
-
30
- def parse(string, options = {})
31
- catch :ZeroWidthParseSuccess do
32
- return super(string, options)
33
- end
34
- @default.clone rescue @default
35
- end
36
-
37
- def eql?(other)
38
- other.instance_of? ParsletRepetitionDefault and @min == other.min and @max == other.max and @parseable.eql? other.parseable and @default == other.default
39
- end
40
-
41
- protected
42
-
43
- # For determining equality.
44
- attr_reader :default
45
-
46
- private
47
-
48
- def hash_offset
49
- 69
50
- end
51
-
52
- def update_hash
53
- @hash = super + @default.hash # let super calculate its share of the hash first
54
- end
55
-
56
- def default=(default)
57
- @default = (default.clone rescue default)
58
- @default.extend(LocationTracking)
59
- update_hash
60
- end
61
-
62
- end # class ParsletRepetitionDefault
63
- end # class Grammar
64
- end # module Walrus
@@ -1,214 +0,0 @@
1
- # Copyright 2007 Wincent Colaiuta
2
- # This program is free software: you can redistribute it and/or modify
3
- # it under the terms of the GNU General Public License as published by
4
- # the Free Software Foundation, either version 3 of the License, or
5
- # (at your option) any later version.
6
- #
7
- # This program is distributed in the hope that it will be useful,
8
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- # GNU General Public License for more details.
11
- #
12
- # You should have received a copy of the GNU General Public License
13
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
-
15
- require 'walrus'
16
-
17
- module Walrus
18
- class Grammar
19
-
20
- class ParsletSequence < ParsletCombination
21
-
22
- attr_reader :hash
23
-
24
- # first and second may not be nil.
25
- def initialize(first, second, *others)
26
- raise ArgumentError if first.nil?
27
- raise ArgumentError if second.nil?
28
- @components = [first, second] + others
29
- update_hash
30
- end
31
-
32
- # Override so that sequences are appended to an existing sequence:
33
- # Consider the following example:
34
- # A & B
35
- # This constitutes a single sequence:
36
- # (A & B)
37
- # If we then make this a three-element sequence:
38
- # A & B & C
39
- # We are effectively creating an nested sequence containing the original sequence and an additional element:
40
- # ((A & B) & C)
41
- # Although such a nested sequence is correctly parsed it produces unwanted nesting in the results because instead of returning a one-dimensional an array of results:
42
- # [a, b, c]
43
- # It returns a nested array:
44
- # [[a, b], c]
45
- # The solution to this unwanted nesting is to allowing appending to an existing sequence by using the private "append" method.
46
- # This ensures that:
47
- # A & B & C
48
- # Translates to a single sequence:
49
- # (A & B & C)
50
- # And a single, uni-dimensional results array:
51
- # [a, b, c]
52
- #
53
- def &(next_parslet)
54
- append(next_parslet)
55
- end
56
-
57
- SKIP_FIRST = true
58
- NO_SKIP = false
59
-
60
- def parse(string, options = {})
61
- parse_common(NO_SKIP, string, options)
62
- end
63
-
64
- def parse_remainder(string, options = {})
65
- parse_common(SKIP_FIRST, string, options)
66
- end
67
-
68
- def parse_common(skip_first, string, options = {})
69
- raise ArgumentError if string.nil?
70
- state = ParserState.new(string, options)
71
- last_caught = nil # keep track of the last kind of throw to be caught
72
- left_recursion = false # keep track of whether left recursion was detected
73
-
74
- @components.each_with_index do |parseable, index|
75
-
76
- if index == 0 # for first component only
77
- if skip_first
78
- next
79
- end
80
- begin
81
- check_left_recursion(parseable, options)
82
- rescue LeftRecursionException => e
83
- left_recursion = true
84
- continuation = nil
85
-
86
- # Ruby 1.9/2.0 will almost certainly not support continuations so need to come up with an alternative
87
- # for handling left recursion here
88
- value = callcc { |c| continuation = c }
89
- if value == continuation # first time that we're here
90
- e.continuation = continuation # pack continuation into exception
91
- raise e # and propagate
92
- else
93
- grammar = state.options[:grammar]
94
- rule_name = state.options[:rule_name]
95
- state.parsed(grammar.wrap(value, rule_name))
96
- next
97
- end
98
- end
99
- end
100
-
101
- catch :ProcessNextComponent do
102
- catch :NotPredicateSuccess do
103
- catch :AndPredicateSuccess do
104
- catch :ZeroWidthParseSuccess do
105
- begin
106
- parsed = parseable.memoizing_parse(state.remainder, state.options)
107
- state.parsed(parsed)
108
- rescue SkippedSubstringException => e
109
- state.skipped(e)
110
- rescue ParseError => e # failed, will try to skip; save original error in case skipping fails
111
- if options.has_key?(:skipping_override)
112
- skipping_parslet = options[:skipping_override]
113
- elsif options.has_key?(:skipping)
114
- skipping_parslet = options[:skipping]
115
- else
116
- skipping_parslet = nil
117
- end
118
- raise e if skipping_parslet.nil? # no skipper defined, raise original error
119
- begin
120
- parsed = skipping_parslet.memoizing_parse(state.remainder, state.options) # guard against self references (possible infinite recursion) here?
121
- state.skipped(parsed)
122
- redo # skipping succeeded, try to redo
123
- rescue ParseError
124
- raise e # skipping didn't help either, raise original error
125
- end
126
- end
127
- last_caught = nil
128
- throw :ProcessNextComponent # can't use "next" here because it would only break out of innermost "do" rather than continuing the iteration
129
- end
130
- last_caught = :ZeroWidthParseSuccess
131
- throw :ProcessNextComponent
132
- end
133
- last_caught = :AndPredicateSuccess
134
- throw :ProcessNextComponent
135
- end
136
- last_caught = :NotPredicateSuccess
137
- end
138
- end
139
-
140
- if left_recursion
141
- results = recurse(state)
142
- else
143
- results = state.results
144
- end
145
-
146
- if skip_first
147
- return results
148
- end
149
-
150
- if results.respond_to? :empty? and results.empty? and last_caught
151
- throw last_caught
152
- else
153
- results
154
- end
155
-
156
- end
157
-
158
- # Left-recursion helper
159
- def recurse(state)
160
- return state.results if state.remainder == '' # further recursion is not possible
161
- new_state = ParserState.new(state.remainder, state.options)
162
- last_successful_result = nil
163
- while state.remainder != ''
164
- begin
165
- new_results = parse_remainder(new_state.remainder, new_state.options)
166
- new_state.parsed(new_results)
167
- last_successful_result = ArrayResult[last_successful_result || state.results, new_results]
168
- rescue ParseError
169
- break
170
- end
171
- end
172
- last_successful_result || state.results
173
- end
174
-
175
- def eql?(other)
176
- return false if not other.instance_of? ParsletSequence
177
- other_components = other.components
178
- return false if @components.length != other_components.length
179
- for i in 0..(@components.length - 1)
180
- return false unless @components[i].eql? other_components[i]
181
- end
182
- true
183
- end
184
-
185
- protected
186
-
187
- # For determining equality.
188
- attr_reader :components
189
-
190
- private
191
-
192
- def hash_offset
193
- 40
194
- end
195
-
196
- def update_hash
197
- @hash = hash_offset # fixed offset to avoid unwanted collisions with similar classes
198
- @components.each { |parseable| @hash += parseable.hash }
199
- end
200
-
201
- # Appends another Parslet, ParsletCombination or Predicate to the receiver and returns the receiver.
202
- # Raises if next_parslet is nil.
203
- # Cannot use << as a method name because Ruby cannot parse it without the self, and self is not allowed as en explicit receiver for private messages.
204
- def append(next_parslet)
205
- raise ArgumentError if next_parslet.nil?
206
- @components << next_parslet.to_parseable
207
- update_hash
208
- self
209
- end
210
-
211
- end # class ParsletSequence
212
- end # class Grammar
213
- end # module Walrus
214
-