walrus 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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,34 +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
- class Parslet
20
-
21
- include Walrus::Grammar::ParsletCombining
22
- include Walrus::Grammar::Memoizing
23
-
24
- def to_parseable
25
- self
26
- end
27
-
28
- def parse(string, options = {})
29
- raise NotImplementedError # subclass responsibility
30
- end
31
-
32
- end # class Parslet
33
- end # class Grammar
34
- end # module Walrus
@@ -1,128 +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 ParsletChoice < ParsletCombination
21
-
22
- attr_reader :hash
23
-
24
- # Either parameter may be a Parslet or a ParsletCombination.
25
- # Neither parmeter may be nil.
26
- def initialize(left, right, *others)
27
- raise ArgumentError if left.nil?
28
- raise ArgumentError if right.nil?
29
- @alternatives = [left, right] + others
30
- update_hash
31
- end
32
-
33
- # Override so that alternatives are appended to an existing sequence:
34
- # Consider the following example:
35
- # A | B
36
- # This constitutes a single choice:
37
- # (A | B)
38
- # If we then make this a three-element sequence:
39
- # A | B | C
40
- # We are effectively creating an nested sequence containing the original sequence and an additional element:
41
- # ((A | B) | C)
42
- # Although such a nested sequence is correctly parsed it is not as architecturally clean as a single sequence without nesting:
43
- # (A | B | C)
44
- # This method allows us to use the architecturally cleaner format.
45
- #
46
- def |(next_parslet)
47
- append(next_parslet)
48
- end
49
-
50
- # First tries to parse the left option, falling back and trying the right option and then the any subsequent options in the others instance variable on failure. If no options successfully complete parsing then an ParseError is raised. Any zero-width parse successes thrown by alternative parsers will flow on to a higher level.
51
- def parse(string, options = {})
52
- raise ArgumentError if string.nil?
53
- error = nil # for error reporting purposes will track which parseable gets farthest to the right before failing
54
- left_recursion = nil # will also track any left recursion that we detect
55
- @alternatives.each do |parseable|
56
- begin
57
- result = parseable.memoizing_parse(string, options) # successful parse
58
- if left_recursion and left_recursion.continuation # and we have a continuation
59
- continuation = left_recursion.continuation # continuations are once-only, one-way tickets
60
- left_recursion = nil # set this to nil so as not to call it again without meaning to
61
- continuation.call(result) # so jump back to where we were before
62
- end
63
- return result
64
- rescue LeftRecursionException => e
65
- left_recursion = e
66
-
67
- # TODO:
68
- # it's not enough to just catch this kind of exception and remember the last one
69
- # may need to accumulate these in an array
70
- # consider the example rule:
71
- # :a, :a & :b | :a & :c | :a & :d | :b
72
- # the first option will raise a LeftRecursionException
73
- # the next option will raise for the same reason
74
- # the third likewise
75
- # finally we get to the fourth option, the first which might succeed
76
- # at that point we should have three continuations
77
- # we should try the first, falling back to the second and third if necessary
78
- # on successfully retrying, need to start all over again and try all the options again, just in case further recursion is possible
79
- # so it is quite complicated
80
- # the question is, is it more complicated than the other ways of getting right-associativity into Walrus-generated parsers?
81
-
82
- rescue ParseError => e
83
- if error.nil?
84
- error = e
85
- else
86
- error = e unless error.rightmost?(e)
87
- end
88
- end
89
- end
90
- raise ParseError.new('no valid alternatives while parsing "%s" (%s)' % [string, error.to_s],
91
- :line_end => error.line_end, :column_end => error.column_end) # should generally report the rightmost error
92
- end
93
-
94
- def eql?(other)
95
- return false if not other.instance_of? ParsletChoice
96
- other_alternatives = other.alternatives
97
- return false if @alternatives.length != other_alternatives.length
98
- for i in 0..(@alternatives.length - 1)
99
- return false unless @alternatives[i].eql? other_alternatives[i]
100
- end
101
- true
102
- end
103
-
104
- protected
105
-
106
- # For determining equality.
107
- attr_reader :alternatives
108
-
109
- private
110
-
111
- def update_hash
112
- @hash = 30 # fixed offset to avoid unwanted collisions with similar classes
113
- @alternatives.each { |parseable| @hash += parseable.hash }
114
- end
115
-
116
- # Appends another Parslet (or ParsletCombination) to the receiver and returns the receiver.
117
- # Raises if parslet is nil.
118
- # 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.
119
- def append(next_parslet)
120
- raise ArgumentError if next_parslet.nil?
121
- @alternatives << next_parslet.to_parseable
122
- update_hash
123
- self
124
- end
125
-
126
- end # class ParsletChoice
127
- end # class Grammar
128
- end # module Walrus
@@ -1,32 +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 ParsletCombination
21
-
22
- include Walrus::Grammar::ParsletCombining
23
- include Walrus::Grammar::Memoizing
24
-
25
- def to_parseable
26
- self
27
- end
28
-
29
- end # module ParsletCombination
30
-
31
- end # class Grammar
32
- end # module Walrus
@@ -1,160 +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
- # The ParsletCombining module, together with the ParsletCombination class and its subclasses, provides simple container classes for encapsulating relationships among Parslets. By storing this information outside of the Parslet objects themselves their design is kept clean and they can become immutable objects which are much more easily copied and shared among multiple rules in a Grammar.
21
- module ParsletCombining
22
-
23
- # Convenience method.
24
- def memoizing_parse(string, options = {})
25
- self.to_parseable.memoizing_parse(string, options)
26
- end
27
-
28
- # Convenience method.
29
- def parse(string, options = {})
30
- self.to_parseable.parse(string, options)
31
- end
32
-
33
- # Defines a sequence of Parslets (or ParsletCombinations).
34
- # Returns a ParsletSequence instance.
35
- def sequence(first, second, *others)
36
- Walrus::Grammar::ParsletSequence.new(first.to_parseable, second.to_parseable, *others)
37
- end
38
-
39
- # Shorthand for ParsletCombining.sequence(first, second).
40
- def &(next_parslet)
41
- self.sequence(self, next_parslet)
42
- end
43
-
44
- # Defines a sequence of Parslets similar to the sequence method but with the difference that the contents of array results from the component parslets will be merged into a single array rather than being added as arrays. To illustrate:
45
- #
46
- # 'foo' & 'bar'.one_or_more # returns results like ['foo', ['bar', 'bar', 'bar']]
47
- # 'foo' >> 'bar'.one_or_more # returns results like ['foo', 'bar', 'bar', 'bar']
48
- #
49
- def merge(first, second, *others)
50
- Walrus::Grammar::ParsletMerge.new(first.to_parseable, second.to_parseable, *others)
51
- end
52
-
53
- # Shorthand for ParsletCombining.sequence(first, second)
54
- def >>(next_parslet)
55
- self.merge(self, next_parslet)
56
- end
57
-
58
- # Defines a choice of Parslets (or ParsletCombinations).
59
- # Returns a ParsletChoice instance.
60
- def choice(left, right, *others)
61
- Walrus::Grammar::ParsletChoice.new(left.to_parseable, right.to_parseable, *others)
62
- end
63
-
64
- # Shorthand for ParsletCombining.choice(left, right)
65
- def |(alternative_parslet)
66
- self.choice(self, alternative_parslet)
67
- end
68
-
69
- # Defines a repetition of the supplied Parslet (or ParsletCombination).
70
- # Returns a ParsletRepetition instance.
71
- def repetition(parslet, min, max)
72
- Walrus::Grammar::ParsletRepetition.new(parslet.to_parseable, min, max)
73
- end
74
-
75
- # Shorthand for ParsletCombining.repetition.
76
- def repeat(min = nil, max = nil)
77
- self.repetition(self, min, max)
78
- end
79
-
80
- def repetition_with_default(parslet, min, max, default)
81
- Walrus::Grammar::ParsletRepetitionDefault.new(parslet.to_parseable, min, max, default)
82
- end
83
-
84
- def repeat_with_default(min = nil, max = nil, default = nil)
85
- self.repetition_with_default(self, min, max, default)
86
- end
87
-
88
- # Shorthand for ParsletCombining.repetition(0, 1).
89
- # This method optionally takes a single parameter specifying what object should be returned as a placeholder when there are no matches; this is useful for packing into ASTs where it may be better to parse an empty Array rather than nil. The specified object is cloned and returned in the event that there are no matches. As a convenience, the specified object is automatically extended using the LocationTracking module (this is a convenience so that you can specify empty Arrays, "[]", rather than explicitly passing an "ArrayResult.new")
90
- def optional(default_return_value = NoParameterMarker.instance)
91
- if default_return_value == NoParameterMarker.instance
92
- self.repeat(0, 1) # default behaviour
93
- else
94
- self.repeat_with_default(0, 1, default_return_value)
95
- end
96
- end
97
-
98
- # Alternative to optional.
99
- def zero_or_one
100
- self.optional
101
- end
102
-
103
- # possible synonym "star"
104
- def zero_or_more(default_return_value = NoParameterMarker.instance)
105
- if default_return_value == NoParameterMarker.instance
106
- self.repeat(0) # default behaviour
107
- else
108
- self.repeat_with_default(0, nil, default_return_value)
109
- end
110
- end
111
-
112
- # possible synonym "plus"
113
- def one_or_more
114
- self.repeat(1)
115
- end
116
-
117
- # Parsing Expression Grammar support.
118
- # Succeeds if parslet succeeds but consumes no input (throws an :AndPredicateSuccess symbol).
119
- def and_predicate(parslet)
120
- Walrus::Grammar::AndPredicate.new(parslet.to_parseable)
121
- end
122
-
123
- # Shorthand for and_predicate
124
- # Strictly speaking, this shorthand breaks with established Ruby practice that "?" at the end of a method name should indicate a method that returns true or false.
125
- def and?
126
- self.and_predicate(self)
127
- end
128
-
129
- # Parsing Expression Grammar support.
130
- # Succeeds if parslet fails (throws a :NotPredicateSuccess symbol).
131
- # Fails if parslet succeeds (raise a ParseError).
132
- # Consumes no output.
133
- # This method will almost invariably be used in conjuntion with the & operator, like this:
134
- # rule :foo, :p1 & :p2.not_predicate
135
- # rule :foo, :p1 & :p2.not!
136
- def not_predicate(parslet)
137
- Walrus::Grammar::NotPredicate.new(parslet.to_parseable)
138
- end
139
-
140
- # Shorthand for not_predicate.
141
- # Strictly speaking, this shorthand breaks with established Ruby practice that "!" at the end of a method name should indicate a destructive behaviour on (mutation of) the receiver.
142
- def not!
143
- self.not_predicate(self)
144
- end
145
-
146
- # Succeeds if parsing succeeds, consuming the output, but doesn't actually return anything.
147
- # This is for elements which are required but which shouldn't appear in the final AST.
148
- def omission(parslet)
149
- Walrus::Grammar::ParsletOmission.new(parslet.to_parseable)
150
- end
151
-
152
- # Shorthand for ParsletCombining.omission
153
- def skip
154
- self.omission(self)
155
- end
156
-
157
- end # module ParsletCombining
158
-
159
- end # class Grammar
160
- end # module Walrus
@@ -1,94 +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 ParsletMerge < ParsletSequence
21
-
22
- def parse(string, options = {})
23
- raise ArgumentError if string.nil?
24
- state = ParserState.new(string, options)
25
- last_caught = nil # keep track of the last kind of throw to be caught
26
- @components.each do |parseable|
27
- catch :ProcessNextComponent do
28
- catch :NotPredicateSuccess do
29
- catch :AndPredicateSuccess do
30
- catch :ZeroWidthParseSuccess do
31
- begin
32
- parsed = parseable.memoizing_parse(state.remainder, state.options)
33
- if parsed.respond_to? :each
34
- parsed.each { |element| state.parsed(element) }
35
- else
36
- state.parsed(parsed)
37
- end
38
- rescue SkippedSubstringException => e
39
- state.skipped(e)
40
- # rescue ParseError => e # failed, will try to skip; save original error in case skipping fails
41
- # if options.has_key?(:skipping_override) : skipping_parslet = options[:skipping_override]
42
- # elsif options.has_key?(:skipping) : skipping_parslet = options[:skipping]
43
- # else skipping_parslet = nil
44
- # end
45
- # raise e if skipping_parslet.nil? # no skipper defined, raise original error
46
- # begin
47
- # parsed = skipping_parslet.memoizing_parse(state.remainder, state.options) # guard against self references (possible infinite recursion) here?
48
- # state.skipped(parsed)
49
- # redo # skipping succeeded, try to redo
50
- # rescue ParseError
51
- # raise e # skipping didn't help either, raise original error
52
- # end
53
- end
54
- last_caught = nil
55
- throw :ProcessNextComponent # can't use "next" here because it will only break out of innermost "do"
56
- end
57
- last_caught = :ZeroWidthParseSuccess
58
- throw :ProcessNextComponent
59
- end
60
- last_caught = :AndPredicateSuccess
61
- throw :ProcessNextComponent
62
- end
63
- last_caught = :NotPredicateSuccess
64
- end
65
- end
66
-
67
- if state.results.respond_to? :empty? and state.results.empty? and
68
- throw last_caught
69
- else
70
- state.results
71
- end
72
-
73
- end
74
-
75
- def eql?(other)
76
- return false if not other.instance_of? ParsletMerge
77
- other_components = other.components
78
- return false if @components.length != other_components.length
79
- for i in 0..(@components.length - 1)
80
- return false unless @components[i].eql? other_components[i]
81
- end
82
- true
83
- end
84
-
85
- private
86
-
87
- def hash_offset
88
- 53
89
- end
90
-
91
- end # class ParsletMerge
92
- end # class Grammar
93
- end # module Walrus
94
-