walrus 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. data/bin/walrus +44 -0
  2. data/ext/jindex/extconf.rb +11 -0
  3. data/ext/jindex/jindex.c +79 -0
  4. data/ext/mkdtemp/extconf.rb +11 -0
  5. data/ext/mkdtemp/mkdtemp.c +41 -0
  6. data/lib/walrus/additions/module.rb +36 -0
  7. data/lib/walrus/additions/string.rb +37 -0
  8. data/lib/walrus/additions/test/unit/error_collector.rb +62 -0
  9. data/lib/walrus/compile_error.rb +28 -0
  10. data/lib/walrus/compiler.rb +124 -0
  11. data/lib/walrus/contrib/spec/walruscloth_spec.rb +32 -0
  12. data/lib/walrus/contrib/walruscloth.rb +82 -0
  13. data/lib/walrus/diff.rb +89 -0
  14. data/lib/walrus/document.rb +98 -0
  15. data/lib/walrus/grammar/additions/proc.rb +20 -0
  16. data/lib/walrus/grammar/additions/regexp.rb +21 -0
  17. data/lib/walrus/grammar/additions/string.rb +52 -0
  18. data/lib/walrus/grammar/additions/symbol.rb +42 -0
  19. data/lib/walrus/grammar/and_predicate.rb +40 -0
  20. data/lib/walrus/grammar/array_result.rb +19 -0
  21. data/lib/walrus/grammar/continuation_wrapper_exception.rb +28 -0
  22. data/lib/walrus/grammar/left_recursion_exception.rb +27 -0
  23. data/lib/walrus/grammar/location_tracking.rb +105 -0
  24. data/lib/walrus/grammar/match_data_wrapper.rb +65 -0
  25. data/lib/walrus/grammar/memoizing.rb +41 -0
  26. data/lib/walrus/grammar/memoizing_cache.rb +94 -0
  27. data/lib/walrus/grammar/node.rb +60 -0
  28. data/lib/walrus/grammar/not_predicate.rb +40 -0
  29. data/lib/walrus/grammar/parse_error.rb +39 -0
  30. data/lib/walrus/grammar/parser_state.rb +181 -0
  31. data/lib/walrus/grammar/parslet.rb +28 -0
  32. data/lib/walrus/grammar/parslet_choice.rb +120 -0
  33. data/lib/walrus/grammar/parslet_combination.rb +26 -0
  34. data/lib/walrus/grammar/parslet_combining.rb +154 -0
  35. data/lib/walrus/grammar/parslet_merge.rb +88 -0
  36. data/lib/walrus/grammar/parslet_omission.rb +57 -0
  37. data/lib/walrus/grammar/parslet_repetition.rb +97 -0
  38. data/lib/walrus/grammar/parslet_repetition_default.rb +58 -0
  39. data/lib/walrus/grammar/parslet_sequence.rb +202 -0
  40. data/lib/walrus/grammar/predicate.rb +57 -0
  41. data/lib/walrus/grammar/proc_parslet.rb +52 -0
  42. data/lib/walrus/grammar/regexp_parslet.rb +73 -0
  43. data/lib/walrus/grammar/skipped_substring_exception.rb +36 -0
  44. data/lib/walrus/grammar/string_enumerator.rb +45 -0
  45. data/lib/walrus/grammar/string_parslet.rb +75 -0
  46. data/lib/walrus/grammar/string_result.rb +24 -0
  47. data/lib/walrus/grammar/symbol_parslet.rb +63 -0
  48. data/lib/walrus/grammar.rb +170 -0
  49. data/lib/walrus/no_parameter_marker.rb +19 -0
  50. data/lib/walrus/parser.rb +420 -0
  51. data/lib/walrus/runner.rb +356 -0
  52. data/lib/walrus/template.rb +75 -0
  53. data/lib/walrus/walrus_grammar/assignment_expression.rb +24 -0
  54. data/lib/walrus/walrus_grammar/block_directive.rb +28 -0
  55. data/lib/walrus/walrus_grammar/comment.rb +24 -0
  56. data/lib/walrus/walrus_grammar/def_directive.rb +64 -0
  57. data/lib/walrus/walrus_grammar/echo_directive.rb +44 -0
  58. data/lib/walrus/walrus_grammar/escape_sequence.rb +24 -0
  59. data/lib/walrus/walrus_grammar/import_directive.rb +44 -0
  60. data/lib/walrus/walrus_grammar/include_directive.rb +27 -0
  61. data/lib/walrus/walrus_grammar/instance_variable.rb +24 -0
  62. data/lib/walrus/walrus_grammar/literal.rb +24 -0
  63. data/lib/walrus/walrus_grammar/message_expression.rb +25 -0
  64. data/lib/walrus/walrus_grammar/multiline_comment.rb +54 -0
  65. data/lib/walrus/walrus_grammar/placeholder.rb +40 -0
  66. data/lib/walrus/walrus_grammar/raw_directive.rb +42 -0
  67. data/lib/walrus/walrus_grammar/raw_text.rb +45 -0
  68. data/lib/walrus/walrus_grammar/ruby_directive.rb +29 -0
  69. data/lib/walrus/walrus_grammar/ruby_expression.rb +31 -0
  70. data/lib/walrus/walrus_grammar/set_directive.rb +24 -0
  71. data/lib/walrus/walrus_grammar/silent_directive.rb +44 -0
  72. data/lib/walrus/walrus_grammar/slurp_directive.rb +25 -0
  73. data/lib/walrus/walrus_grammar/super_directive.rb +27 -0
  74. data/lib/walrus.rb +64 -0
  75. data/spec/acceptance/acceptance_spec.rb +97 -0
  76. data/spec/acceptance/block/basic_block.expected +1 -0
  77. data/spec/acceptance/block/basic_block.tmpl +3 -0
  78. data/spec/acceptance/block/nested_blocks.expected +5 -0
  79. data/spec/acceptance/block/nested_blocks.tmpl +11 -0
  80. data/spec/acceptance/comments/comments_and_text.expected +3 -0
  81. data/spec/acceptance/comments/comments_and_text.tmpl +6 -0
  82. data/spec/acceptance/comments/single_comment.expected +0 -0
  83. data/spec/acceptance/comments/single_comment.tmpl +1 -0
  84. data/spec/acceptance/def/alternative_def_calling_conventions.expected +3 -0
  85. data/spec/acceptance/def/alternative_def_calling_conventions.tmpl +18 -0
  86. data/spec/acceptance/def/basic_def_block_no_output.expected +0 -0
  87. data/spec/acceptance/def/basic_def_block_no_output.tmpl +17 -0
  88. data/spec/acceptance/def/defs_can_be_called_multiple_times.expected +3 -0
  89. data/spec/acceptance/def/defs_can_be_called_multiple_times.tmpl +6 -0
  90. data/spec/acceptance/def/defs_can_be_dynamic.expected +4 -0
  91. data/spec/acceptance/def/defs_can_be_dynamic.tmpl +12 -0
  92. data/spec/acceptance/echo/echo_directive_with_numeric_literal.expected +1 -0
  93. data/spec/acceptance/echo/echo_directive_with_numeric_literal.tmpl +1 -0
  94. data/spec/acceptance/echo/echo_expression_list.expected +1 -0
  95. data/spec/acceptance/echo/echo_expression_list.tmpl +1 -0
  96. data/spec/acceptance/echo/echo_short_notation.expected +1 -0
  97. data/spec/acceptance/echo/echo_short_notation.tmpl +1 -0
  98. data/spec/acceptance/echo/echo_simple_expression.expected +1 -0
  99. data/spec/acceptance/echo/echo_simple_expression.tmpl +1 -0
  100. data/spec/acceptance/echo/echo_single_quoted_string_literal.expected +1 -0
  101. data/spec/acceptance/echo/echo_single_quoted_string_literal.tmpl +1 -0
  102. data/spec/acceptance/echo/multiple_echo_statements.expected +1 -0
  103. data/spec/acceptance/echo/multiple_echo_statements.tmpl +2 -0
  104. data/spec/acceptance/includes/basic_included_file.txt +1 -0
  105. data/spec/acceptance/includes/basic_includer.complex +3 -0
  106. data/spec/acceptance/includes/basic_includer.expected +3 -0
  107. data/spec/acceptance/includes/basic_includer.rb +38 -0
  108. data/spec/acceptance/includes/complicated_included_file.txt +3 -0
  109. data/spec/acceptance/includes/complicated_includer.complex +3 -0
  110. data/spec/acceptance/includes/complicated_includer.expected +3 -0
  111. data/spec/acceptance/includes/complicated_includer.rb +41 -0
  112. data/spec/acceptance/includes/nested_include_1.txt +3 -0
  113. data/spec/acceptance/includes/nested_include_2.txt +1 -0
  114. data/spec/acceptance/includes/nested_includer.complex +3 -0
  115. data/spec/acceptance/includes/nested_includer.expected +4 -0
  116. data/spec/acceptance/includes/nested_includer.rb +41 -0
  117. data/spec/acceptance/inheritance/basic_child.complex +10 -0
  118. data/spec/acceptance/inheritance/basic_child.expected +9 -0
  119. data/spec/acceptance/inheritance/basic_child.rb +54 -0
  120. data/spec/acceptance/inheritance/basic_parent.complex +5 -0
  121. data/spec/acceptance/inheritance/basic_parent.expected +3 -0
  122. data/spec/acceptance/inheritance/basic_parent.rb +41 -0
  123. data/spec/acceptance/inheritance/importing_child.complex +8 -0
  124. data/spec/acceptance/inheritance/importing_child.expected +7 -0
  125. data/spec/acceptance/inheritance/importing_child.rb +46 -0
  126. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.complex +8 -0
  127. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.expected +7 -0
  128. data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.rb +44 -0
  129. data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.expected +0 -0
  130. data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.tmpl +15 -0
  131. data/spec/acceptance/multiline_comments/simple_multiline_comment.expected +2 -0
  132. data/spec/acceptance/multiline_comments/simple_multiline_comment.tmpl +4 -0
  133. data/spec/acceptance/raw/complicated_raw_example.expected +57 -0
  134. data/spec/acceptance/raw/complicated_raw_example.tmpl +79 -0
  135. data/spec/acceptance/raw-text/UTF_8.expected +12 -0
  136. data/spec/acceptance/raw-text/UTF_8.tmpl +12 -0
  137. data/spec/acceptance/raw-text/empty_file.expected +0 -0
  138. data/spec/acceptance/raw-text/empty_file.tmpl +0 -0
  139. data/spec/acceptance/raw-text/multi_line.expected +4 -0
  140. data/spec/acceptance/raw-text/multi_line.tmpl +4 -0
  141. data/spec/acceptance/raw-text/single_line.expected +1 -0
  142. data/spec/acceptance/raw-text/single_line.tmpl +1 -0
  143. data/spec/acceptance/raw-text/single_line_whitespace.expected +1 -0
  144. data/spec/acceptance/raw-text/single_line_whitespace.tmpl +1 -0
  145. data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.expected +1 -0
  146. data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.tmpl +4 -0
  147. data/spec/acceptance/ruby/ruby_directive_using_here_doc.expected +1 -0
  148. data/spec/acceptance/ruby/ruby_directive_using_here_doc.tmpl +4 -0
  149. data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.expected +1 -0
  150. data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.tmpl +4 -0
  151. data/spec/acceptance/ruby/ruby_directive_with_accumulate.expected +1 -0
  152. data/spec/acceptance/ruby/ruby_directive_with_accumulate.tmpl +4 -0
  153. data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.expected +1 -0
  154. data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.tmpl +6 -0
  155. data/spec/acceptance/set/unused_set.expected +0 -0
  156. data/spec/acceptance/set/unused_set.tmpl +1 -0
  157. data/spec/acceptance/set/used_set.expected +1 -0
  158. data/spec/acceptance/set/used_set.tmpl +2 -0
  159. data/spec/acceptance/silent/silent_and_echo_combined.expected +1 -0
  160. data/spec/acceptance/silent/silent_and_echo_combined.tmpl +2 -0
  161. data/spec/acceptance/silent/silent_short_notation.expected +1 -0
  162. data/spec/acceptance/silent/silent_short_notation.tmpl +1 -0
  163. data/spec/acceptance/silent/simple_silent_directive.expected +0 -0
  164. data/spec/acceptance/silent/simple_silent_directive.tmpl +1 -0
  165. data/spec/acceptance/slurp/basic_slurp_demo.expected +1 -0
  166. data/spec/acceptance/slurp/basic_slurp_demo.tmpl +4 -0
  167. data/spec/acceptance/super/super_with_no_effect.expected +4 -0
  168. data/spec/acceptance/super/super_with_no_effect.tmpl +5 -0
  169. data/spec/additions/module_spec.rb +126 -0
  170. data/spec/additions/string_spec.rb +99 -0
  171. data/spec/compiler_spec.rb +55 -0
  172. data/spec/grammar/additions/proc_spec.rb +25 -0
  173. data/spec/grammar/additions/regexp_spec.rb +37 -0
  174. data/spec/grammar/additions/string_spec.rb +106 -0
  175. data/spec/grammar/and_predicate_spec.rb +29 -0
  176. data/spec/grammar/continuation_wrapper_exception_spec.rb +23 -0
  177. data/spec/grammar/match_data_wrapper_spec.rb +41 -0
  178. data/spec/grammar/memoizing_cache_spec.rb +112 -0
  179. data/spec/grammar/node_spec.rb +126 -0
  180. data/spec/grammar/not_predicate_spec.rb +29 -0
  181. data/spec/grammar/parser_state_spec.rb +172 -0
  182. data/spec/grammar/parslet_choice_spec.rb +49 -0
  183. data/spec/grammar/parslet_combining_spec.rb +287 -0
  184. data/spec/grammar/parslet_merge_spec.rb +33 -0
  185. data/spec/grammar/parslet_omission_spec.rb +58 -0
  186. data/spec/grammar/parslet_repetition_spec.rb +77 -0
  187. data/spec/grammar/parslet_sequence_spec.rb +49 -0
  188. data/spec/grammar/parslet_spec.rb +23 -0
  189. data/spec/grammar/predicate_spec.rb +53 -0
  190. data/spec/grammar/proc_parslet_spec.rb +52 -0
  191. data/spec/grammar/regexp_parslet_spec.rb +347 -0
  192. data/spec/grammar/string_enumerator_spec.rb +94 -0
  193. data/spec/grammar/string_parslet_spec.rb +143 -0
  194. data/spec/grammar/symbol_parslet_spec.rb +30 -0
  195. data/spec/grammar_spec.rb +545 -0
  196. data/spec/parser_spec.rb +1418 -0
  197. data/spec/spec_helper.rb +34 -0
  198. data/spec/walrus_grammar/comment_spec.rb +39 -0
  199. data/spec/walrus_grammar/echo_directive_spec.rb +63 -0
  200. data/spec/walrus_grammar/escape_sequence_spec.rb +85 -0
  201. data/spec/walrus_grammar/literal_spec.rb +41 -0
  202. data/spec/walrus_grammar/message_expression_spec.rb +37 -0
  203. data/spec/walrus_grammar/multiline_comment_spec.rb +58 -0
  204. data/spec/walrus_grammar/placeholder_spec.rb +48 -0
  205. data/spec/walrus_grammar/raw_directive_spec.rb +81 -0
  206. data/spec/walrus_grammar/raw_text_spec.rb +65 -0
  207. data/spec/walrus_grammar/silent_directive_spec.rb +34 -0
  208. metadata +291 -0
@@ -0,0 +1,89 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+ require 'open3'
11
+ require 'pathname'
12
+ require 'tempfile'
13
+
14
+ # Simple wrapper for diff(1).
15
+ class Diff
16
+
17
+ def initialize(left, right)
18
+ raise ArgumentError.new('left may not be nil') unless left
19
+ raise ArgumentError.new('right may not be nil') unless right
20
+
21
+ # keep a copy of the parameters (used by the diff method)
22
+ @left = left.clone
23
+ @right = right.clone
24
+
25
+ if left.kind_of? Pathname and right.kind_of? Pathname
26
+ @output = self.compare_pathname_with_pathname(left, right)
27
+ elsif left.kind_of? String and right.kind_of? Pathname
28
+ @output = self.compare_string_with_pathname(left, right)
29
+ elsif left.kind_of? Pathname and right.kind_of? String
30
+ @output = self.compare_pathname_with_string(left, right)
31
+ elsif left.kind_of? String and right.kind_of? String
32
+ @output = self.compare_string_with_string(left, right)
33
+ else
34
+ raise ArgumentError.new('unsupported argument types (%s, %s)' % [left.class.to_s, right.class.to_s])
35
+ end
36
+
37
+ end
38
+
39
+ def compare_pathname_with_pathname(left, right)
40
+ self.diff(left.realpath, right.realpath)
41
+ end
42
+
43
+ def compare_string_with_pathname(left, right)
44
+ # will pipe left in over standard input
45
+ self.diff('-', right.realpath)
46
+ end
47
+
48
+ def compare_pathname_with_string(left, right)
49
+ # will pipe right in over standard input
50
+ self.diff(left.realpath, '-')
51
+ end
52
+
53
+ # This is the least secure comparison method because it requires the creation of a temporary file and Ruby's builtin Tempfile class is not secure.
54
+ def compare_string_with_string(left, right)
55
+ # incorporate a psuedo-random component to make race conditions more difficult to exploit
56
+ tempfile = Tempfile.new('walrus-%s' % rand(100000).to_s)
57
+ tempfile.unlink # shut the race condition vulnerability window as soon as possible
58
+ tempfile.write(left)
59
+ tempfile.close
60
+ self.diff(tempfile.path, "-")
61
+ end
62
+
63
+ # Actually runs diff(1) with the supplied arguments (pathnames). One but not both of the arguments may be "-" to indicate the standard input.
64
+ def self.diff(left, right)
65
+ raise ArgumentError.new('left may not be ni') unless left
66
+ raise ArgumentError.new('right may not be nil') unless right
67
+ raise ArgumentError.new('only one parameter may be "-"') if left == '-' and right == '-'
68
+
69
+ # no shell involved, so no need to escape shell metacharacters
70
+ Open3.popen3('diff', '-u', left, right) do |stdin, stdout, stderr|
71
+ if left == '-'
72
+ stdin.write(@left)
73
+ elsif right == '-'
74
+ stdin.write(@right)
75
+ end
76
+ stdin.close_write
77
+
78
+ # TODO: decide what to do with stderr output (if any)
79
+ stderr.read
80
+ return stdout.read
81
+ end
82
+
83
+ end
84
+
85
+ def to_s
86
+ @output
87
+ end
88
+
89
+ end
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright 2007 Wincent Colaiuta
4
+ # This program is distributed in the hope that it will be useful, but WITHOUT
5
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
7
+ # in the accompanying file, "LICENSE.txt", for more details.
8
+ #
9
+ # $Id: /mirrors/Walrus/trunk/walrus/lib/walrus/document.rb 6708 2007-04-10T05:38:35.035099Z wincent $
10
+
11
+ require 'walrus'
12
+ require 'pathname'
13
+
14
+ module Walrus
15
+
16
+ # All compiled templates inherit from this class.
17
+ class Document
18
+
19
+ def initialize
20
+ @internal_hash = {}
21
+ end
22
+
23
+ def set_value(key, value)
24
+ @internal_hash[key.to_sym] = value
25
+ end
26
+
27
+ def get_value(key)
28
+ @internal_hash[key.to_sym]
29
+ end
30
+
31
+ def remove_value(key)
32
+ @internal_hash.delete(key.to_sym)
33
+ end
34
+
35
+ # Expects a placeholder symbol or String.
36
+ # The parameters are optional.
37
+ def lookup_and_accumulate_placeholder(placeholder, *params)
38
+ output = lookup_and_return_placeholder(placeholder, *params)
39
+ accumulate(output) if output
40
+ end
41
+
42
+ def lookup_and_return_placeholder(placeholder, *params)
43
+ # if exists a method responding to placeholder, call it
44
+ if respond_to? placeholder
45
+ @accumulators << nil # push new accumulator onto the stack
46
+ output = send(placeholder, *params) # call method
47
+ accumulated = @accumulators.pop # pop last accumulator from the stack
48
+ if accumulated
49
+ return accumulated
50
+ elsif output
51
+ return output
52
+ end
53
+ else # otherwise, try looking it up in the values hash
54
+ return get_value(placeholder)
55
+ end
56
+ end
57
+
58
+ # Supports two calling methods:
59
+ # - if passed a string it will be appended to the accumulator.
60
+ # - if not passed a string but given a block will evaluate the block and append the (string) result to the accumulator.
61
+ def accumulate(string = nil)
62
+ if (@accumulators.last.nil?) # accumulator will be nil if hasn't been used yet
63
+ @accumulators.pop # replace temporary nil accumulator
64
+ @accumulators.push("") # with proper string accumulator
65
+ end
66
+ if block_given?
67
+ @accumulators.last << yield.to_s
68
+ elsif not string.nil?
69
+ @accumulators.last << string.to_s
70
+ end
71
+ end
72
+
73
+ # Fills (executes) the template body of the receiver and returns the result.
74
+ def fill
75
+ @accumulators = [nil] # reset accumulators stack
76
+ template_body
77
+ @accumulators.last or ""
78
+ end
79
+
80
+ # Prints to standard out the result of filling the receiver. Note that no trailing newline is printed. As a result, if running a template from the terminal be aware that the last line may not be visible or may be partly obscured by the command prompt that is drawn (starting at the first column) after execution completes.
81
+ def run
82
+ printf('%s', fill)
83
+ $stdout.flush
84
+ end
85
+
86
+ # By default, there is nothing at all in the template body.
87
+ def template_body
88
+ end
89
+
90
+ if __FILE__ == $0
91
+ self.new.run # When run from the command line the default action is to call "run".
92
+ else
93
+ self.new.fill # in other cases, evaluate 'fill' (if run inside an eval, will return filled content)
94
+ end
95
+
96
+ end # class Document
97
+ end # module Walrus
98
+
@@ -0,0 +1,20 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ class Proc
12
+
13
+ include Walrus::Grammar::ParsletCombining
14
+
15
+ # Returns a ProcParslet based on the receiver
16
+ def to_parseable
17
+ Walrus::Grammar::ProcParslet.new(self)
18
+ end
19
+
20
+ end # class Proc
@@ -0,0 +1,21 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ class Regexp
12
+
13
+ require 'walrus/grammar/parslet_combining'
14
+ include Walrus::Grammar::ParsletCombining
15
+
16
+ # Returns a RegexpParslet based on the receiver
17
+ def to_parseable
18
+ Walrus::Grammar::RegexpParslet.new(self)
19
+ end
20
+
21
+ end # class Regexp
@@ -0,0 +1,52 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ require 'jindex' # multibyte-friendly implementations of String#index and String#rindex
12
+
13
+ # Additions to String class for Unicode support.
14
+ class String
15
+
16
+ # Returns an array of Unicode characters.
17
+ def chars
18
+ scan(/./m)
19
+ end
20
+
21
+ alias old_range []
22
+
23
+ # multi-byte friendly [] implementation
24
+ def [](range, other = Walrus::NoParameterMarker.instance)
25
+ if other == Walrus::NoParameterMarker.instance
26
+ if range.kind_of? Range
27
+ chars[range].join
28
+ else
29
+ old_range range
30
+ end
31
+ else
32
+ old_range range, other
33
+ end
34
+ end
35
+
36
+ # Returns a character-level enumerator for the receiver.
37
+ def enumerator
38
+ Walrus::Grammar::StringEnumerator.new(self)
39
+ end
40
+
41
+ end # class String
42
+
43
+ class String
44
+
45
+ include Walrus::Grammar::ParsletCombining # Rationale: it's ok to add "&" and "|" methods to string because they don't exist yet (they're not overrides).
46
+
47
+ # Returns a StringParslet based on the receiver
48
+ def to_parseable
49
+ Walrus::Grammar::StringParslet.new(self)
50
+ end
51
+
52
+ end # class String
@@ -0,0 +1,42 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ class Symbol
12
+
13
+ include Walrus::Grammar::ParsletCombining
14
+
15
+ # Returns a SymbolParslet based on the receiver.
16
+ # Symbols can be used in Grammars when specifying rules and productions to refer to other rules and productions that have not been defined yet.
17
+ # They can also be used to allow self-references within rules and productions (recursion); for example:
18
+ # rule :thing & :thing.optional & :other_thing
19
+ # Basically these SymbolParslets allow deferred evaluation of a rule or production (deferred until parsing takes place) rather than being evaluated at the time a rule or production is defined.
20
+ def to_parseable
21
+ Walrus::Grammar::SymbolParslet.new(self)
22
+ end
23
+
24
+ # Dynamically creates a subclass named after the receiver, with parent class superclass, taking params.
25
+ def build(superclass, *params)
26
+
27
+ # first use the continuation trick to find out what grammar (namespace) receiver is being messaged in
28
+ continuation = nil
29
+ value = callcc { |c| continuation = c }
30
+ if value == continuation # first time that we're here
31
+ raise Walrus::Grammar::ContinuationWrapperException.new(continuation) # give higher up a chance to help us
32
+ else # value is the Grammar instance passed to us from higher up using call on the continuation
33
+ grammar = value
34
+ end
35
+
36
+ # actually create the subclass
37
+ grammar.const_get(superclass.to_s.to_class_name.to_s).subclass(self.to_s.to_class_name.to_s, grammar, *params)
38
+ self
39
+
40
+ end
41
+
42
+ end # class Symbol
@@ -0,0 +1,40 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ class AndPredicate < Predicate
15
+
16
+ def parse(string, options = {})
17
+ raise ArgumentError if string.nil?
18
+ catch :ZeroWidthParseSuccess do
19
+ begin
20
+ parsed = @parseable.memoizing_parse(string, options)
21
+ rescue ParseError
22
+ raise ParseError.new('predicate not satisfied (expected "%s") while parsing "%s"' % [@parseable.to_s, string],
23
+ :line_end => options[:line_start], :column_end => options[:column_start])
24
+ end
25
+ end
26
+
27
+ # getting this far means that parsing succeeded (just what we wanted)
28
+ throw :AndPredicateSuccess # pass succeeded
29
+ end
30
+
31
+ private
32
+
33
+ def hash_offset
34
+ 12
35
+ end
36
+
37
+ end
38
+
39
+ end # class Grammar
40
+ end # module Walrus
@@ -0,0 +1,19 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+ class ArrayResult < Array
14
+
15
+ include LocationTracking
16
+
17
+ end # class ArrayResult
18
+ end # class Grammar
19
+ end # module Walrus
@@ -0,0 +1,28 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ class ContinuationWrapperException < Exception
15
+
16
+ attr_reader :continuation
17
+
18
+ def initialize(continuation)
19
+ raise ArgumentError if continuation.nil?
20
+ super self.class.to_s
21
+ @continuation = continuation
22
+ end
23
+
24
+ end # class ContinuationWrapperException
25
+
26
+ end # class Grammar
27
+ end # module Walrus
28
+
@@ -0,0 +1,27 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ class LeftRecursionException < Exception
15
+
16
+ attr_accessor :continuation
17
+
18
+ def initialize(continuation = nil)
19
+ super self.class.to_s
20
+ @continuation = continuation
21
+ end
22
+
23
+ end # class LeftRecursionException
24
+
25
+ end # class Grammar
26
+ end # module Walrus
27
+
@@ -0,0 +1,105 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id: /mirrors/Walrus/trunk/walrus/lib/walrus/grammar/location_tracking.rb 6704 2007-04-09T18:30:00.421185Z wincent $
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ # Methods for embedding location information in objects returned (or exceptions raised) from parse methods.
15
+ module LocationTracking
16
+
17
+ attr_reader :source_text
18
+
19
+ # For occasions where a single item must serve as a carrier for array-like information
20
+ # (that is, its own start, end and source_text, as well as the "outer" equivalents).
21
+ # This can happen where a single node appears in a list context surrounded only by skipped content.
22
+ attr_accessor :outer_start, :outer_end, :outer_source_text
23
+
24
+ def source_text=(string)
25
+ @source_text = string.to_s.clone
26
+ end
27
+
28
+ # Sets @column_start to col.
29
+ # Sets @column_start to 0 if passed nil (for ease of use, users of classes that mix-in this module don't have to worry about special casing nil values).
30
+ def column_start=(column_start)
31
+ @column_start = column_start.to_i
32
+ end
33
+
34
+ # Returns 0 if @column_start is nil (for ease of use, users of classes that mix-in this module don't have to worry about special casing nil values).
35
+ def column_start
36
+ @column_start || 0
37
+ end
38
+
39
+ # Sets @line_start to line.
40
+ # Sets @line_start to 0 if passed nil (for ease of use, users of classes that mix-in this module don't have to worry about special casing nil values).
41
+ def line_start=(line_start)
42
+ @line_start = line_start.to_i
43
+ end
44
+
45
+ # Returns 0 if @line_start is nil (for ease of use, users of classes that mix-in this module don't have to worry about special casing nil values).
46
+ def line_start
47
+ @line_start || 0
48
+ end
49
+
50
+ # Convenience method for getting both line_start and column_start at once.
51
+ def start
52
+ [self.line_start, self.column_start]
53
+ end
54
+
55
+ # Convenience method for setting both line_start and column_start at once.
56
+ def start=(array)
57
+ raise ArgumentError if array.nil?
58
+ raise ArgumentError if array.length != 2
59
+ self.line_start = array[0]
60
+ self.column_start = array[1]
61
+ end
62
+
63
+ def line_end=(line_end)
64
+ @line_end = line_end.to_i
65
+ end
66
+
67
+ def line_end
68
+ @line_end || 0
69
+ end
70
+
71
+ def column_end=(column_end)
72
+ @column_end = column_end.to_i
73
+ end
74
+
75
+ def column_end
76
+ @column_end || 0
77
+ end
78
+
79
+ # Convenience method for getting both line_end and column_end at once.
80
+ def end
81
+ [self.line_end, self.column_end]
82
+ end
83
+
84
+ # Convenience method for setting both line_end and column_end at once.
85
+ def end=(array)
86
+ raise ArgumentError if array.nil?
87
+ raise ArgumentError if array.length != 2
88
+ self.line_end = array[0]
89
+ self.column_end = array[1]
90
+ end
91
+
92
+ # Given another object that responds to column_end and line_end, returns true if the receiver is rightmost or equal.
93
+ # If the other object is farther to the right returns false.
94
+ def rightmost?(other)
95
+ if self.line_end > other.line_end : true
96
+ elsif other.line_end > self.line_end : false
97
+ elsif self.column_end >= other.column_end : true
98
+ else false
99
+ end
100
+ end
101
+
102
+ end # module LocationTracking
103
+
104
+ end # class Grammar
105
+ end # module Walrus
@@ -0,0 +1,65 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ # Simple wrapper for MatchData objects that implements length, to_s and to_str methods.
15
+ # By implementing to_str, MatchDataWrappers can be directly compared with Strings using the == method.
16
+ # The original MatchData instance can be obtained using the match_data accessor.
17
+ # Upon creation a clone of the passed in MatchData object is stored; this means that the $~ global variable can be conveniently wrapped without having to worry that subsequent operations will alter the contents of the variable.
18
+ class MatchDataWrapper
19
+
20
+ include Walrus::Grammar::LocationTracking
21
+
22
+ attr_reader :match_data
23
+
24
+ # Raises if data is nil.
25
+ def initialize(data)
26
+ raise ArgumentError if data.nil?
27
+ self.match_data = data
28
+ end
29
+
30
+ # The definition of this method, in conjunction with the == method, allows automatic comparisons with String objects using the == method.
31
+ # This is because in a parser matches essentially are Strings (just like Exceptions and Pathnames); it's just that this class encapsulates a little more information (the match data) for those who want it.
32
+ def to_str
33
+ self.to_s
34
+ end
35
+
36
+ # Although this method explicitly allows for MatchDataWrapper to MatchDataWrapper comparisons, not that all such comparisons will return false except for those between instances which were initialized with exactly the same match data instance; this is because the MatchData class itself always returns false when compared with other MatchData instances.
37
+ def ==(other)
38
+ if other.kind_of? MatchDataWrapper
39
+ self.match_data == other.match_data
40
+ elsif other.respond_to? :to_str
41
+ self.to_str == other.to_str
42
+ else
43
+ false
44
+ end
45
+ end
46
+
47
+ def to_s
48
+ @match_data[0]
49
+ end
50
+
51
+ def jlength
52
+ self.to_s.jlength
53
+ end
54
+
55
+ private
56
+
57
+ def match_data=(data)
58
+ @match_data = (data.clone rescue data)
59
+ end
60
+
61
+ end # class MatchDataWrapper
62
+
63
+ end # class Grammar
64
+ end # module Walrus
65
+
@@ -0,0 +1,41 @@
1
+ # Copyright 2007 Wincent Colaiuta
2
+ # This program is distributed in the hope that it will be useful, but WITHOUT
3
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5
+ # in the accompanying file, "LICENSE.txt", for more details.
6
+ #
7
+ # $Id$
8
+
9
+ require 'walrus'
10
+
11
+ module Walrus
12
+ class Grammar
13
+
14
+ module Memoizing
15
+
16
+ # This method provides a clean, optional implementation of memoizing by serving as a wrapper for all parse invocations. Rather than calling the parse methods directly, this method should be called; if it is appropriate to use a memoizer then it will be invoked, otherwise control will fall through to the real parse method. Turning off memoizing is as simple as not parsing a value with the :memoizer key in the options hash.
17
+ # This method defined is in a separate module so that it can easily be mixed in with all Parslets, ParsletCombinations and Predicates.
18
+ def memoizing_parse(string, options = {})
19
+
20
+ # Will use memoizer if available and not instructed to ignore it
21
+ if options.has_key?(:memoizer) and not (options.has_key?(:ignore_memoizer) and options[:ignore_memoizer])
22
+ options[:parseable] = self
23
+ options[:memoizer].parse(string, options)
24
+ else # otherwise will proceed as normal
25
+ options[:ignore_memoizer] = false
26
+ parse(string, options)
27
+ end
28
+
29
+ end
30
+
31
+ # Can only check for left recursion if memoizing is turned on (the help of the memoizer is needed).
32
+ def check_left_recursion(parseable, options = {})
33
+ return unless options.has_key?(:memoizer)
34
+ options[:memoizer].check_left_recursion(parseable, options)
35
+ end
36
+
37
+ end # module Memoizing
38
+
39
+ end # class Grammar
40
+ end # module Walrus
41
+