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,426 +1,44 @@
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.
1
+ # Copyright 2007-2010 Wincent Colaiuta. All rights reserved.
2
+ # Redistribution and use in source and binary forms, with or without
3
+ # modification, are permitted provided that the following conditions are met:
6
4
  #
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.
5
+ # 1. Redistributions of source code must retain the above copyright notice,
6
+ # this list of conditions and the following disclaimer.
7
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
8
+ # this list of conditions and the following disclaimer in the documentation
9
+ # and/or other materials provided with the distribution.
11
10
  #
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/>.
11
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
15
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
19
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
+ # POSSIBILITY OF SUCH DAMAGE.
14
22
 
15
23
  require 'walrus'
16
24
  require 'pathname'
17
25
 
18
26
  module Walrus
19
-
20
27
  # The parser is currently quite slow, although perfectly usable.
21
- # The quickest route to optimizing it may be to replace it with a C parser inside a Ruby extension,
22
- # possibly generated using Ragel: http://www.cs.queensu.ca/~thurston/ragel/
28
+ # The quickest route to optimizing it may be to replace it with a C parser
29
+ # inside a Ruby extension, possibly generated using Ragel
23
30
  class Parser
24
-
25
- def parse(string, options = {})
26
- @@grammar.parse(string, options)
31
+ def parse string, options = {}
32
+ Grammar.new.parse string, options
27
33
  end
28
-
29
- def compile(string, options = {})
34
+
35
+ def compile string, options = {}
30
36
  @@compiler ||= Compiler.new
31
37
  parsed = []
32
- catch :AndPredicateSuccess do # catch here because an empty file will throw
38
+ catch :AndPredicateSuccess do # catch here because empty files throw
33
39
  parsed = parse string, options
34
40
  end
35
41
  @@compiler.compile parsed, options
36
42
  end
37
-
38
- @@grammar ||= Grammar.subclass('WalrusGrammar') do
39
-
40
- starting_symbol :template
41
-
42
- skipping :whitespace_or_newlines
43
-
44
- rule :whitespace_or_newlines, /\s+/
45
-
46
- # only spaces and tabs, not newlines
47
- rule :whitespace, /[ \t\v]+/
48
- rule :newline, /(\r\n|\r|\n)/
49
-
50
- # optional whitespace (tabs and spaces only) followed by a backslash/newline (note: this is not escape-aware)
51
- rule :line_continuation, /[ \t\v]*\\\n/
52
- rule :end_of_input, /\z/
53
-
54
- rule :template, :template_element.zero_or_more & :end_of_input.and?
55
- rule :template_element, :raw_text | :comment | :multiline_comment | :directive | :placeholder |:escape_sequence
56
-
57
- # anything at all other than the three characters which have special meaning in Walrus: $, \ and #
58
- rule :raw_text, /[^\$\\#]+/
59
- production :raw_text.build(:node)
60
-
61
- node :literal
62
-
63
- rule :string_literal, :single_quoted_string_literal | :double_quoted_string_literal
64
- skipping :string_literal, nil
65
- node :string_literal, :literal
66
-
67
- rule :single_quoted_string_literal, "'".skip & :single_quoted_string_content.optional & "'".skip
68
- production :single_quoted_string_literal.build(:string_literal)
69
- rule :single_quoted_string_content, /(\\(?!').|\\'|[^'\\]+)+/
70
- rule :double_quoted_string_literal, '"'.skip & :double_quoted_string_content.optional & '"'.skip
71
- production :double_quoted_string_literal.build(:string_literal)
72
- rule :double_quoted_string_content, /(\\(?!").|\\"|[^"\\]+)+/
73
-
74
- # TODO: support 1_000_000 syntax for numeric_literals
75
- rule :numeric_literal, /\d+\.\d+|\d+(?!\.)/
76
- production :numeric_literal.build(:literal)
77
-
78
- # this matches both "foo" and "Foo::bar"
79
- rule :identifier, /([A-Z][a-zA-Z0-9_]*::)*[a-z_][a-zA-Z0-9_]*/
80
- production :identifier.build(:literal)
81
-
82
- # this matches both "Foo" and "Foo::Bar"
83
- rule :constant, /([A-Z][a-zA-Z0-9_]*::)*[A-Z][a-zA-Z0-9_]*/
84
- production :constant.build(:literal)
85
-
86
- rule :symbol_literal, /:[a-zA-Z_][a-zA-Z0-9_]*/
87
- production :symbol_literal.build(:literal)
88
-
89
- rule :escape_sequence, '\\'.skip & /[\$\\#]/
90
- production :escape_sequence.build(:node)
91
-
92
- rule :comment, '##'.skip & /.*$/
93
- production :comment.build(:node)
94
-
95
- # nested multiline comments
96
- rule :multiline_comment, '#*'.skip & :comment_content.zero_or_more('') & '*#'.skip
97
- skipping :multiline_comment, nil
98
- production :multiline_comment.build(:comment, :content)
99
-
100
- rule :comment_content, (:comment & :newline.skip) |
101
- :multiline_comment |
102
- /( # three possibilities:
103
- [^*#]+ | # 1. any run of characters other than # or *
104
- \#(?!\#|\*) | # 2. any # not followed by another # or a *
105
- \*(?!\#) # 3. any * not followed by a #
106
- )+ # match the three possibilities repeatedly
107
- /x
108
-
109
- rule :directive, :block_directive |
110
- :def_directive |
111
- :echo_directive |
112
- :extends_directive |
113
- :import_directive |
114
- :include_directive |
115
- :raw_directive |
116
- :ruby_directive |
117
- :set_directive |
118
- :silent_directive |
119
- :slurp_directive |
120
- :super_directive
121
-
122
- node :directive
123
-
124
- # directives may span multiple lines if and only if the last character on the line is a backslash \
125
- skipping :directive, :whitespace | :line_continuation
126
-
127
- # "Directive tags can be closed explicitly with #, or implicitly with the end of the line"
128
- # http://www.cheetahtemplate.org/docs/users_guide_html_multipage/language.directives.closures.html
129
- # This means that to follow a directive by a comment on the same line you must explicitly close the directive first (otherwise the grammar would be ambiguous).
130
- # Note that "skipping" the end_of_input here is harmless as it isn't actually consumed.
131
- rule :directive_end, ( /#/ | :newline | :end_of_input ).skip
132
-
133
- rule :block_directive, '#block'.skip & :identifier & :def_parameter_list.optional([]) & :directive_end &
134
- :template_element.zero_or_more([]) &
135
- '#end'.skip & :directive_end
136
-
137
- rule :def_directive, '#def'.skip & :identifier & :def_parameter_list.optional([]) & :directive_end &
138
- :template_element.zero_or_more([]) &
139
- '#end'.skip & :directive_end
140
-
141
- production :def_directive.build(:directive, :identifier, :params, :content) # superclass (DefDirective) must be created
142
- production :block_directive.build(:def_directive, :identifier, :params, :content) # before the subclass (BlockDirective)
143
-
144
- # "The #echo directive is used to echo the output from expressions that can't be written as simple $placeholders."
145
- # http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.echo.html
146
- #
147
- # Convenient alternative short syntax for the #echo directive, similar to ERB (http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/):
148
- #
149
- # #= expression(s) #
150
- #
151
- # Is a shortcut equivalent to:
152
- #
153
- # #echo expression(s) #
154
- #
155
- # This is similar to the ERB syntax, but even more concise:
156
- #
157
- # <%= expression(s) =>
158
- #
159
- # See also the #silent directive, which also has a shortcut syntax.
160
- #
161
- rule :echo_directive, '#echo'.skip & :ruby_expression_list & :directive_end | # long form
162
- '#='.skip & :ruby_expression_list & '#'.skip # short form
163
- production :echo_directive.build(:directive, :expression)
164
-
165
- rule :extends_directive, '#extends'.skip & :string_literal & :directive_end
166
- rule :import_directive, '#import'.skip & :string_literal & :directive_end
167
- production :import_directive.build(:directive, :class_name) # superclass (ImportDirective) must be created
168
- production :extends_directive.build(:import_directive, :class_name) # before the subclass (ExtendsDirective)
169
-
170
- rule :include_directive, '#include'.skip & :include_subparslet
171
- production :include_directive.build(:directive, :file_name, :subtree)
172
-
173
- rule :include_subparslet, lambda { |string, options|
174
-
175
- # scans a string literal
176
- parslet = :string_literal & :directive_end
177
- file_name = parslet.parse(string, options)
178
-
179
- # if options contains non-nil "origin" then try to construct relative path; otherwise just look in current working directory
180
- if options[:origin]
181
- current_location = Pathname.new(options[:origin]).dirname
182
- include_target = current_location + file_name.to_s
183
- else
184
- include_target = Pathname.new file_name.to_s
185
- end
186
-
187
- # read file into string
188
- content = include_target.read
189
-
190
- # try to parse string in sub-parser
191
- sub_options = { :origin => include_target.to_s }
192
- sub_result = nil
193
- catch :AndPredicateSuccess do
194
- sub_result = Parser.new.parse(content, sub_options)
195
- end
196
-
197
- # want to insert a bunch of nodes (a subtree) into the parse tree without advancing the location counters
198
- sub_tree = Grammar::ArrayResult.new [ file_name, sub_result ? sub_result : [] ]
199
- sub_tree.start = file_name.start
200
- sub_tree.end = file_name.end
201
- sub_tree
202
- }
203
-
204
- # "Any section of a template definition that is inside a #raw ... #end raw tag pair will be printed verbatim without any parsing of $placeholders or other directives."
205
- # http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.raw.html
206
- # Unlike Cheetah, Walrus uses a bare "#end" marker and not an "#end raw" to mark the end of the raw block.
207
- # The presence of a literal #end within a raw block is made possible by using an optional "here doc"-style delimiter:
208
- #
209
- # #raw <<END_MARKER
210
- # content goes here
211
- # END_MARKER
212
- #
213
- # Here the opening "END_MARKER" must be the last thing on the line (trailing whitespace up to and including the newline is allowed but it is not considered to be part of the quoted text). The final "END_MARKER" must be the very first and last thing on the line, or it will not be considered to be an end marker at all and will be considered part of the quoted text. The newline immediately prior to the end marker is included in the quoted text.
214
- #
215
- # Or, if the end marker is to be indented:
216
- #
217
- # #raw <<-END_MARKER
218
- # content
219
- # END_MARKER
220
- #
221
- # Here "END_MARKER" may be preceeded by whitespace (and whitespace only) but it must be the last thing on the line. The preceding whitespace is not considered to be part of the quoted text.
222
- rule :raw_directive, '#raw'.skip & ((:directive_end & /([^#]+|#(?!end)+)*/ & '#end'.skip & :directive_end) | :here_document)
223
- production :raw_directive.build(:directive, :content)
224
-
225
- # In order to parse "here documents" we adopt a model similar to the one proposed in this message to the ANTLR interest list:
226
- # http://www.antlr.org:8080/pipermail/antlr-interest/2005-September/013673.html
227
- rule :here_document, lambda { |string, options|
228
-
229
- # for the time-being, not sure if there is much benefit in calling memoizing_parse here
230
- state = Grammar::ParserState.new(string, options)
231
- parsed = /<<(-?)([a-zA-Z0-9_]+)[ \t\v]*\n/.to_parseable.parse(state.remainder, state.options)
232
- state.skipped(parsed)
233
- marker = parsed.match_data
234
- indenting = (marker[1] == '') ? false : true
235
-
236
- if indenting # whitespace allowed before end marker
237
- end_marker = /^[ \t\v]*#{marker[2]}[ \t\v]*(\n|\z)/.to_parseable # will eat trailing newline
238
- else # no whitespace allowed before end marker
239
- end_marker = /^#{marker[2]}[ \t\v]*(\n|\z)/.to_parseable # will eat trailing newline
240
- end
241
-
242
- line = /^.*\n/.to_parseable # for gobbling a line
243
-
244
- while true do
245
- begin
246
- skipped = end_marker.parse(state.remainder, state.options)
247
- state.skipped(skipped) # found end marker, skip it
248
- break # all done
249
- rescue Grammar::ParseError # didn't find end marker yet, consume a line
250
- parsed = line.parse(state.remainder, state.options)
251
- state.parsed(parsed)
252
- end
253
- end
254
-
255
- # caller will want a String, not an Array
256
- results = state.results
257
- document = Grammar::StringResult.new(results.to_s)
258
- document.start = results.start
259
- document.end = results.end
260
- document
261
- }
262
-
263
- rule :ruby_directive, '#ruby'.skip & ((:directive_end & /([^#]+|#(?!end)+)*/ & '#end'.skip & :directive_end) | :here_document)
264
- production :ruby_directive.build(:directive, :content)
265
-
266
- # Unlike a normal Ruby assignement expression, the lvalue of a "#set" directive is an identifier preceded by a dollar sign.
267
- rule :set_directive, '#set'.skip & /\$(?![ \r\n\t\v])/.skip & :placeholder_name & '='.skip & (:addition_expression | :unary_expression) & :directive_end
268
- production :set_directive.build(:directive, :placeholder, :expression)
269
-
270
- # "#silent is the opposite of #echo. It executes an expression but discards the output."
271
- # http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.silent.html
272
- #
273
- # Like the #echo directive, a convienient shorthand syntax is available:
274
- #
275
- # # expressions(s) #
276
- #
277
- # Equivalent to the long form:
278
- #
279
- # #silent expressions(s) #
280
- #
281
- # And similar to but more concise than the ERB syntax:
282
- #
283
- # <% expressions(s) %>
284
- #
285
- # Note that the space between the opening hash character and the expression(s) is required in order for Walrus to distinguish the shorthand for the #silent directive from the other directives. That is, the following is not legal:
286
- #
287
- # #expressions(s) #
288
- #
289
- rule :silent_directive, '#silent'.skip & :ruby_expression_list & :directive_end | # long form
290
- '# '.skip & :ruby_expression_list & '#'.skip # short form
291
- production :silent_directive.build(:directive, :expression)
292
-
293
- # Accept multiple expressions separated by a semi-colon.
294
- rule :ruby_expression_list, :ruby_expression >> (';'.skip & :ruby_expression ).zero_or_more
295
-
296
- # "The #slurp directive eats up the trailing newline on the line it appears in, joining the following line onto the current line."
297
- # http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.slurp.html
298
- # The "slurp" directive must be the last thing on the line (not followed by a comment or directive end marker)
299
- rule :slurp_directive, '#slurp' & :whitespace.optional.skip & :newline.skip
300
- production :slurp_directive.build(:directive)
301
-
302
- rule :super_directive, :super_with_parentheses | :super_without_parentheses
303
- node :super_directive
304
- rule :super_with_parentheses, '#super'.skip & :parameter_list.optional & :directive_end
305
- production :super_with_parentheses.build(:super_directive, :params)
306
- rule :super_without_parentheses, '#super'.skip & :parameter_list_without_parentheses & :directive_end
307
- production :super_without_parentheses.build(:super_directive, :params)
308
-
309
- # The "def_parameter_list" is a special case of parameter list which disallows interpolated placeholders.
310
- rule :def_parameter_list, '('.skip & ( :def_parameter >> ( ','.skip & :def_parameter ).zero_or_more ).optional & ')'.skip
311
- rule :def_parameter, :assignment_expression | :identifier
312
-
313
- rule :parameter_list, '('.skip & ( :parameter >> ( ','.skip & :parameter ).zero_or_more ).optional & ')'.skip
314
- rule :parameter_list_without_parentheses, :parameter >> ( ','.skip & :parameter ).zero_or_more
315
- rule :parameter, :placeholder | :ruby_expression
316
-
317
- # placeholders may be in long form (${foo}) or short form ($foo)
318
- rule :placeholder, :long_placeholder | :short_placeholder
319
- node :placeholder
320
-
321
- # No whitespace allowed between the "$" and the opening "{"
322
- rule :long_placeholder, '${'.skip & :placeholder_name & :placeholder_parameters.optional([]) & '}'.skip
323
- production :long_placeholder.build(:placeholder, :name, :params)
324
-
325
- # No whitespace allowed between the "$" and the placeholder_name
326
- rule :short_placeholder, /\$(?![ \r\n\t\v])/.skip & :placeholder_name & :placeholder_parameters.optional([])
327
- production :short_placeholder.build(:placeholder, :name, :params)
328
-
329
- rule :placeholder_name, :identifier
330
- rule :placeholder_parameters, '('.skip & (:placeholder_parameter >> (','.skip & :placeholder_parameter).zero_or_more).optional & ')'.skip
331
- rule :placeholder_parameter, :placeholder | :ruby_expression
332
-
333
- # simplified Ruby subset
334
- rule :ruby_expression, :assignment_expression | :addition_expression | :unary_expression
335
- node :ruby_expression
336
-
337
- rule :literal_expression, :string_literal |
338
- :numeric_literal |
339
- :array_literal |
340
- :hash_literal |
341
- :lvalue |
342
- :symbol_literal
343
- rule :unary_expression, :message_expression | :literal_expression
344
-
345
- rule :lvalue, :class_variable | :instance_variable | :identifier | :constant
346
-
347
- rule :array_literal, '['.skip & ( :ruby_expression >> (','.skip & :ruby_expression ).zero_or_more ).optional & ']'.skip
348
- production :array_literal.build(:ruby_expression, :elements)
349
-
350
- rule :hash_literal, '{'.skip & ( :hash_assignment >> (','.skip & :hash_assignment ).zero_or_more ).optional & '}'.skip
351
- production :hash_literal.build(:ruby_expression, :pairs)
352
-
353
- rule :hash_assignment, :unary_expression & '=>'.skip & (:addition_expression | :unary_expression)
354
- production :hash_assignment.build(:ruby_expression, :lvalue, :expression)
355
-
356
- rule :assignment_expression, :lvalue & '='.skip & (:addition_expression | :unary_expression)
357
- production :assignment_expression.build(:ruby_expression, :lvalue, :expression)
358
-
359
- # addition is left-associative (left-recursive)
360
- rule :addition_expression, :addition_expression & '+'.skip & :unary_expression |
361
- :unary_expression & '+'.skip & :unary_expression
362
-
363
- production :addition_expression.build(:ruby_expression, :left, :right)
364
-
365
- # message expressions are left-associative (left-recursive)
366
- rule :message_expression, :message_expression & '.'.skip & :method_expression |
367
- :literal_expression & '.'.skip & :method_expression
368
- production :message_expression.build(:ruby_expression, :target, :message)
369
-
370
- rule :method_expression, :method_with_parentheses | :method_without_parentheses
371
- node :method_expression, :ruby_expression
372
-
373
- rule :method_with_parentheses, :identifier & :method_parameter_list.optional([])
374
- production :method_with_parentheses.build(:method_expression, :name, :params)
375
- rule :method_without_parentheses, :identifier & :method_parameter_list_without_parentheses
376
- production :method_without_parentheses.build(:method_expression, :name, :params)
377
-
378
- rule :method_parameter_list, '('.skip & ( :method_parameter >> ( ','.skip & :method_parameter ).zero_or_more ).optional & ')'.skip
379
- rule :method_parameter, :ruby_expression
380
- rule :method_parameter_list_without_parentheses, :method_parameter >> ( ','.skip & :method_parameter ).zero_or_more
381
-
382
- rule :class_variable, '@@'.skip & :identifier
383
- skipping :class_variable, nil
384
- production :class_variable.build(:ruby_expression)
385
-
386
- rule :instance_variable, '@'.skip & :identifier
387
- skipping :instance_variable, nil
388
- production :instance_variable.build(:ruby_expression)
389
-
390
- # TODO: regexp literal expression
391
-
392
- # Ruby + allowing placeholders for unary expressions
393
- rule :extended_ruby_expression, :extended_unary_expression | :ruby_expression
394
- node :extended_ruby_expression
395
-
396
- rule :extended_unary_expression, :placeholder | :unary_expression
397
-
398
- # only after defining the grammar is it safe to extend the classes dynamically created during the grammar definition
399
- # TODO: modify the code which creates classes on the fly so that the requires are no longer order-sensitive
400
- require 'walrus/walrus_grammar/assignment_expression'
401
- require 'walrus/walrus_grammar/block_directive'
402
- require 'walrus/walrus_grammar/comment'
403
- require 'walrus/walrus_grammar/def_directive'
404
- require 'walrus/walrus_grammar/echo_directive'
405
- require 'walrus/walrus_grammar/escape_sequence'
406
- require 'walrus/walrus_grammar/import_directive'
407
- require 'walrus/walrus_grammar/include_directive'
408
- require 'walrus/walrus_grammar/instance_variable'
409
- require 'walrus/walrus_grammar/literal'
410
- require 'walrus/walrus_grammar/message_expression'
411
- require 'walrus/walrus_grammar/multiline_comment'
412
- require 'walrus/walrus_grammar/placeholder'
413
- require 'walrus/walrus_grammar/raw_directive'
414
- require 'walrus/walrus_grammar/raw_text'
415
- require 'walrus/walrus_grammar/ruby_directive'
416
- require 'walrus/walrus_grammar/ruby_expression'
417
- require 'walrus/walrus_grammar/set_directive'
418
- require 'walrus/walrus_grammar/silent_directive'
419
- require 'walrus/walrus_grammar/slurp_directive'
420
- require 'walrus/walrus_grammar/super_directive'
421
-
422
- end
423
-
424
43
  end # class Parser
425
-
426
44
  end # module Walrus
@@ -1,16 +1,24 @@
1
- # Copyright 2007-2009 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.
1
+ # Copyright 2007-2010 Wincent Colaiuta. All rights reserved.
2
+ # Redistribution and use in source and binary forms, with or without
3
+ # modification, are permitted provided that the following conditions are met:
6
4
  #
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.
5
+ # 1. Redistributions of source code must retain the above copyright notice,
6
+ # this list of conditions and the following disclaimer.
7
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
8
+ # this list of conditions and the following disclaimer in the documentation
9
+ # and/or other materials provided with the distribution.
11
10
  #
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/>.
11
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
15
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
19
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
+ # POSSIBILITY OF SUCH DAMAGE.
14
22
 
15
23
  require 'walrus'
16
24
  require 'fileutils'
@@ -24,6 +32,8 @@ module Walrus
24
32
  class Runner
25
33
  class Error < Exception ; end
26
34
 
35
+ # This is different from the standard ::ArgumentError; it is specifically
36
+ # used to signal errors in the command-line arguments passed to the runner.
27
37
  class ArgumentError < Error ; end
28
38
 
29
39
  def initialize
@@ -44,14 +54,21 @@ module Walrus
44
54
  parser = OptionParser.new do |o|
45
55
  o.banner = "Usage: #{o.program_name} command input-file(s)-or-directory/ies [options]"
46
56
  o.separator ''
47
- o.separator ' _____________'
48
- o.separator ' / \\'
49
- o.separator " / o o \\ #{o.program_name}"
50
- o.separator ' | b | Command-line front-end for the Walrus templating system'
51
- o.separator ' \\ ~-----~ / Copyright 2007 Wincent Colaiuta'
52
- o.separator ' \\ / / \\ \\ /'
53
- o.separator ' / /-----\\ \\'
54
- o.separator ' |_/ \\_|'
57
+ o.separator " ___"
58
+ o.separator " .-9 9 `\\ #{o.program_name} version #{Walrus::VERSION}"
59
+ o.separator " =(:(::)= ; Command-line front-end for the Walrus templating system"
60
+ o.separator " |||| \\ #{Walrus::COPYRIGHT}"
61
+ o.separator " |||| `-."
62
+ o.separator " ,\\|\\| `,"
63
+ o.separator " / \\"
64
+ o.separator " ; `'---.,"
65
+ o.separator " | `\\"
66
+ o.separator " ; / |"
67
+ o.separator " \\ | /"
68
+ o.separator " ) \\ __,.--\\ /"
69
+ o.separator " .-' \\,..._\\ \\` .-' .-'"
70
+ o.separator " `-=`` `: | /-/-/`"
71
+ o.separator " `.__/ jgs"
55
72
  o.separator ''
56
73
  o.separator 'Commands: compile -- compile templates to Ruby code'
57
74
  o.separator ' fill -- runs compiled templates, writing output to disk'
@@ -213,7 +230,7 @@ module Walrus
213
230
 
214
231
  begin
215
232
  compiled = template.compile
216
- rescue Grammar::ParseError => e
233
+ rescue Walrat::ParseError => e
217
234
  handle_error("failed to compile input template '#{template_source_path}' (#{e.to_s})")
218
235
  return
219
236
  end