walrus 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/walrus +19 -12
- data/lib/walrus.rb +27 -70
- data/lib/walrus/additions/string.rb +21 -35
- data/lib/walrus/compile_error.rb +19 -16
- data/lib/walrus/compiler.rb +66 -55
- data/lib/walrus/contrib/spec/walruscloth_spec.rb +21 -17
- data/lib/walrus/contrib/walruscloth.rb +19 -11
- data/lib/walrus/document.rb +41 -33
- data/lib/walrus/grammar.rb +474 -162
- data/lib/walrus/grammar/assignment_expression.rb +33 -0
- data/lib/walrus/grammar/block_directive.rb +37 -0
- data/lib/walrus/grammar/comment.rb +33 -0
- data/lib/walrus/grammar/def_directive.rb +80 -0
- data/lib/walrus/grammar/echo_directive.rb +56 -0
- data/lib/walrus/grammar/escape_sequence.rb +33 -0
- data/lib/walrus/grammar/import_directive.rb +54 -0
- data/lib/walrus/grammar/include_directive.rb +36 -0
- data/lib/walrus/grammar/instance_variable.rb +33 -0
- data/lib/walrus/grammar/literal.rb +33 -0
- data/lib/walrus/grammar/message_expression.rb +34 -0
- data/lib/walrus/grammar/multiline_comment.rb +70 -0
- data/lib/walrus/grammar/placeholder.rb +47 -0
- data/lib/walrus/grammar/raw_directive.rb +50 -0
- data/lib/walrus/grammar/raw_text.rb +56 -0
- data/lib/walrus/grammar/ruby_directive.rb +41 -0
- data/lib/walrus/grammar/ruby_expression.rb +42 -0
- data/lib/walrus/grammar/set_directive.rb +34 -0
- data/lib/walrus/grammar/silent_directive.rb +51 -0
- data/lib/walrus/grammar/slurp_directive.rb +36 -0
- data/lib/walrus/grammar/super_directive.rb +34 -0
- data/lib/walrus/parser.rb +26 -408
- data/lib/walrus/runner.rb +37 -20
- data/lib/walrus/template.rb +34 -25
- data/lib/walrus/version.rb +24 -1
- metadata +57 -71
- data/ext/extconf.rb +0 -16
- data/ext/jindex.c +0 -92
- data/lib/walrus/diff.rb +0 -95
- data/lib/walrus/grammar/additions/proc.rb +0 -26
- data/lib/walrus/grammar/additions/regexp.rb +0 -27
- data/lib/walrus/grammar/additions/string.rb +0 -58
- data/lib/walrus/grammar/additions/symbol.rb +0 -49
- data/lib/walrus/grammar/and_predicate.rb +0 -46
- data/lib/walrus/grammar/array_result.rb +0 -25
- data/lib/walrus/grammar/continuation_wrapper_exception.rb +0 -34
- data/lib/walrus/grammar/left_recursion_exception.rb +0 -33
- data/lib/walrus/grammar/location_tracking.rb +0 -115
- data/lib/walrus/grammar/match_data_wrapper.rb +0 -71
- data/lib/walrus/grammar/memoizing.rb +0 -47
- data/lib/walrus/grammar/memoizing_cache.rb +0 -103
- data/lib/walrus/grammar/node.rb +0 -66
- data/lib/walrus/grammar/not_predicate.rb +0 -46
- data/lib/walrus/grammar/parse_error.rb +0 -45
- data/lib/walrus/grammar/parser_state.rb +0 -187
- data/lib/walrus/grammar/parslet.rb +0 -34
- data/lib/walrus/grammar/parslet_choice.rb +0 -128
- data/lib/walrus/grammar/parslet_combination.rb +0 -32
- data/lib/walrus/grammar/parslet_combining.rb +0 -160
- data/lib/walrus/grammar/parslet_merge.rb +0 -94
- data/lib/walrus/grammar/parslet_omission.rb +0 -63
- data/lib/walrus/grammar/parslet_repetition.rb +0 -106
- data/lib/walrus/grammar/parslet_repetition_default.rb +0 -64
- data/lib/walrus/grammar/parslet_sequence.rb +0 -214
- data/lib/walrus/grammar/predicate.rb +0 -63
- data/lib/walrus/grammar/proc_parslet.rb +0 -58
- data/lib/walrus/grammar/regexp_parslet.rb +0 -79
- data/lib/walrus/grammar/skipped_substring_exception.rb +0 -42
- data/lib/walrus/grammar/string_enumerator.rb +0 -53
- data/lib/walrus/grammar/string_parslet.rb +0 -81
- data/lib/walrus/grammar/string_result.rb +0 -30
- data/lib/walrus/grammar/symbol_parslet.rb +0 -69
- data/lib/walrus/no_parameter_marker.rb +0 -25
- data/lib/walrus/walrus_grammar/assignment_expression.rb +0 -30
- data/lib/walrus/walrus_grammar/block_directive.rb +0 -34
- data/lib/walrus/walrus_grammar/comment.rb +0 -30
- data/lib/walrus/walrus_grammar/def_directive.rb +0 -72
- data/lib/walrus/walrus_grammar/echo_directive.rb +0 -50
- data/lib/walrus/walrus_grammar/escape_sequence.rb +0 -30
- data/lib/walrus/walrus_grammar/import_directive.rb +0 -50
- data/lib/walrus/walrus_grammar/include_directive.rb +0 -33
- data/lib/walrus/walrus_grammar/instance_variable.rb +0 -30
- data/lib/walrus/walrus_grammar/literal.rb +0 -30
- data/lib/walrus/walrus_grammar/message_expression.rb +0 -31
- data/lib/walrus/walrus_grammar/multiline_comment.rb +0 -60
- data/lib/walrus/walrus_grammar/placeholder.rb +0 -46
- data/lib/walrus/walrus_grammar/raw_directive.rb +0 -48
- data/lib/walrus/walrus_grammar/raw_text.rb +0 -51
- data/lib/walrus/walrus_grammar/ruby_directive.rb +0 -35
- data/lib/walrus/walrus_grammar/ruby_expression.rb +0 -37
- data/lib/walrus/walrus_grammar/set_directive.rb +0 -30
- data/lib/walrus/walrus_grammar/silent_directive.rb +0 -50
- data/lib/walrus/walrus_grammar/slurp_directive.rb +0 -31
- data/lib/walrus/walrus_grammar/super_directive.rb +0 -33
@@ -1,38 +1,42 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# it under the terms of the GNU General Public License as published by
|
5
|
-
# the Free Software Foundation, either version 3 of the License, or
|
6
|
-
# (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:
|
7
4
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
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.
|
12
10
|
#
|
13
|
-
#
|
14
|
-
#
|
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.
|
15
22
|
|
16
23
|
require 'rubygems'
|
17
24
|
require 'spec'
|
18
25
|
require File.join(File.dirname(__FILE__), '..', 'walruscloth')
|
19
26
|
|
20
27
|
describe 'using WalrusCloth' do
|
21
|
-
|
22
28
|
it 'should be able to create an unordered list' do
|
23
29
|
# => "<ul>\n\t<li>hello</li>\n\t</ul>"
|
24
30
|
WalrusCloth.new('* hello').to_html.should == RedCloth.new('* hello').to_html
|
25
31
|
end
|
26
|
-
|
32
|
+
|
27
33
|
it 'should be able to create an ordered list' do
|
28
34
|
# => "<ol>\n\t<li>hello</li>\n\t</ol>"
|
29
35
|
WalrusCloth.new('` hello').to_html.should == RedCloth.new('# hello').to_html
|
30
36
|
end
|
31
|
-
|
37
|
+
|
32
38
|
it 'should be able to nest lists' do
|
33
39
|
# => "<ol>\n\t<li>hello\n\t<ul>\n\t<li>world</li>\n\t</ol></li>\n\t</ul>"
|
34
40
|
WalrusCloth.new("` hello\n`* world").to_html.should == RedCloth.new("# hello\n#* world").to_html
|
35
41
|
end
|
36
|
-
|
37
42
|
end
|
38
|
-
|
@@ -1,16 +1,24 @@
|
|
1
|
-
# Copyright 2007 Wincent Colaiuta
|
2
|
-
#
|
3
|
-
#
|
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
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
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
|
-
#
|
13
|
-
#
|
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 'rubygems'
|
16
24
|
gem 'RedCloth', '= 3.0.4'; require 'redcloth'
|
data/lib/walrus/document.rb
CHANGED
@@ -1,56 +1,60 @@
|
|
1
|
-
|
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:
|
2
4
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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.
|
8
10
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# MERCHANTABILITY
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
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.
|
16
22
|
|
17
23
|
require 'walrus'
|
18
24
|
require 'pathname'
|
19
25
|
|
20
26
|
module Walrus
|
21
|
-
|
22
27
|
# All compiled templates inherit from this class.
|
23
28
|
class Document
|
24
|
-
|
25
29
|
def initialize
|
26
30
|
@internal_hash = {}
|
27
31
|
end
|
28
|
-
|
32
|
+
|
29
33
|
def set_value(key, value)
|
30
34
|
@internal_hash[key.to_sym] = value
|
31
35
|
end
|
32
|
-
|
36
|
+
|
33
37
|
def get_value(key)
|
34
38
|
@internal_hash[key.to_sym]
|
35
39
|
end
|
36
|
-
|
40
|
+
|
37
41
|
def remove_value(key)
|
38
42
|
@internal_hash.delete(key.to_sym)
|
39
43
|
end
|
40
|
-
|
44
|
+
|
41
45
|
# Expects a placeholder symbol or String.
|
42
46
|
# The parameters are optional.
|
43
47
|
def lookup_and_accumulate_placeholder(placeholder, *params)
|
44
48
|
output = lookup_and_return_placeholder(placeholder, *params)
|
45
49
|
accumulate(output) if output
|
46
50
|
end
|
47
|
-
|
51
|
+
|
48
52
|
def lookup_and_return_placeholder(placeholder, *params)
|
49
53
|
# if exists a method responding to placeholder, call it
|
50
54
|
if respond_to? placeholder
|
51
|
-
@accumulators << nil
|
52
|
-
output = send(placeholder, *params)
|
53
|
-
accumulated = @accumulators.pop
|
55
|
+
@accumulators << nil # push new accumulator onto the stack
|
56
|
+
output = send(placeholder, *params) # call method
|
57
|
+
accumulated = @accumulators.pop # pop last accumulator from the stack
|
54
58
|
if accumulated
|
55
59
|
return accumulated
|
56
60
|
elsif output
|
@@ -60,10 +64,11 @@ module Walrus
|
|
60
64
|
return get_value(placeholder)
|
61
65
|
end
|
62
66
|
end
|
63
|
-
|
67
|
+
|
64
68
|
# Supports two calling methods:
|
65
69
|
# - if passed a string it will be appended to the accumulator.
|
66
|
-
# - if not passed a string but given a block will evaluate the block and
|
70
|
+
# - if not passed a string but given a block will evaluate the block and
|
71
|
+
# append the (string) result to the accumulator.
|
67
72
|
def accumulate(string = nil)
|
68
73
|
if (@accumulators.last.nil?) # accumulator will be nil if hasn't been used yet
|
69
74
|
@accumulators.pop # replace temporary nil accumulator
|
@@ -75,30 +80,33 @@ module Walrus
|
|
75
80
|
@accumulators.last << string.to_s
|
76
81
|
end
|
77
82
|
end
|
78
|
-
|
79
|
-
# Fills (executes) the template body of the receiver and returns the
|
83
|
+
|
84
|
+
# Fills (executes) the template body of the receiver and returns the
|
85
|
+
# result.
|
80
86
|
def fill
|
81
87
|
@accumulators = [nil] # reset accumulators stack
|
82
88
|
template_body
|
83
89
|
@accumulators.last or ""
|
84
90
|
end
|
85
|
-
|
86
|
-
# Prints to standard out the result of filling the receiver. Note that no
|
91
|
+
|
92
|
+
# Prints to standard out the result of filling the receiver. Note that no
|
93
|
+
# trailing newline is printed. As a result, if running a template from the
|
94
|
+
# terminal be aware that the last line may not be visible or may be partly
|
95
|
+
# obscured by the command prompt that is drawn (starting at the first
|
96
|
+
# column) after execution completes.
|
87
97
|
def run
|
88
98
|
printf('%s', fill)
|
89
99
|
$stdout.flush
|
90
100
|
end
|
91
|
-
|
101
|
+
|
92
102
|
# By default, there is nothing at all in the template body.
|
93
103
|
def template_body
|
94
104
|
end
|
95
|
-
|
105
|
+
|
96
106
|
if __FILE__ == $0
|
97
107
|
self.new.run # When run from the command line the default action is to call "run".
|
98
108
|
else
|
99
109
|
self.new.fill # in other cases, evaluate 'fill' (if run inside an eval, will return filled content)
|
100
110
|
end
|
101
|
-
|
102
111
|
end # class Document
|
103
112
|
end # module Walrus
|
104
|
-
|
data/lib/walrus/grammar.rb
CHANGED
@@ -1,176 +1,488 @@
|
|
1
|
-
# Copyright 2007 Wincent Colaiuta
|
2
|
-
#
|
3
|
-
#
|
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
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
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
|
-
#
|
13
|
-
#
|
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
|
|
23
|
+
require 'walrat/grammar'
|
15
24
|
require 'walrus'
|
25
|
+
require 'pathname'
|
16
26
|
|
17
27
|
module Walrus
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
28
|
+
# The parser is currently quite slow, although perfectly usable.
|
29
|
+
# The quickest route to optimizing it may be to replace it with a C parser
|
30
|
+
# inside a Ruby extension, possibly generated using Ragel
|
31
|
+
class Grammar < Walrat::Grammar
|
32
|
+
autoload :AssignmentExpression, 'walrus/grammar/assignment_expression'
|
33
|
+
autoload :BlockDirective, 'walrus/grammar/block_directive'
|
34
|
+
autoload :Comment, 'walrus/grammar/comment'
|
35
|
+
autoload :DefDirective, 'walrus/grammar/def_directive'
|
36
|
+
autoload :EchoDirective, 'walrus/grammar/echo_directive'
|
37
|
+
autoload :EscapeSequence, 'walrus/grammar/escape_sequence'
|
38
|
+
autoload :ImportDirective, 'walrus/grammar/import_directive'
|
39
|
+
autoload :IncludeDirective, 'walrus/grammar/include_directive'
|
40
|
+
autoload :InstanceVariable, 'walrus/grammar/instance_variable'
|
41
|
+
autoload :Literal, 'walrus/grammar/literal'
|
42
|
+
autoload :MessageExpression, 'walrus/grammar/message_expression'
|
43
|
+
autoload :MultilineComment, 'walrus/grammar/multiline_comment'
|
44
|
+
autoload :Placeholder, 'walrus/grammar/placeholder'
|
45
|
+
autoload :RawDirective, 'walrus/grammar/raw_directive'
|
46
|
+
autoload :RawText, 'walrus/grammar/raw_text'
|
47
|
+
autoload :RubyDirective, 'walrus/grammar/ruby_directive'
|
48
|
+
autoload :RubyExpression, 'walrus/grammar/ruby_expression'
|
49
|
+
autoload :SetDirective, 'walrus/grammar/set_directive'
|
50
|
+
autoload :SilentDirective, 'walrus/grammar/silent_directive'
|
51
|
+
autoload :SlurpDirective, 'walrus/grammar/slurp_directive'
|
52
|
+
autoload :SuperDirective, 'walrus/grammar/super_directive'
|
53
|
+
|
54
|
+
starting_symbol :template
|
55
|
+
skipping :whitespace_or_newlines
|
56
|
+
rule :whitespace_or_newlines,
|
57
|
+
/\s+/
|
58
|
+
|
59
|
+
# only spaces and tabs, not newlines
|
60
|
+
rule :whitespace,
|
61
|
+
/[ \t\v]+/
|
62
|
+
rule :newline,
|
63
|
+
/(\r\n|\r|\n)/
|
64
|
+
|
65
|
+
# optional whitespace (tabs and spaces only) followed by a
|
66
|
+
# backslash/newline (note: this is not escape-aware)
|
67
|
+
rule :line_continuation,
|
68
|
+
/[ \t\v]*\\\n/
|
69
|
+
rule :end_of_input,
|
70
|
+
/\z/
|
71
|
+
|
72
|
+
rule :template,
|
73
|
+
:template_element.zero_or_more &
|
74
|
+
:end_of_input.and?
|
75
|
+
rule :template_element,
|
76
|
+
:raw_text |
|
77
|
+
:comment |
|
78
|
+
:multiline_comment |
|
79
|
+
:directive |
|
80
|
+
:placeholder |
|
81
|
+
:escape_sequence
|
82
|
+
|
83
|
+
# anything at all other than the three characters which have special
|
84
|
+
# meaning in Walrus: $, \ and #
|
85
|
+
rule :raw_text, /[^\$\\#]+/
|
86
|
+
production :raw_text
|
87
|
+
|
88
|
+
rule :string_literal,
|
89
|
+
:single_quoted_string_literal |
|
90
|
+
:double_quoted_string_literal
|
91
|
+
skipping :string_literal, nil
|
92
|
+
node :string_literal, :literal
|
93
|
+
|
94
|
+
rule :single_quoted_string_literal,
|
95
|
+
"'".skip &
|
96
|
+
:single_quoted_string_content.optional &
|
97
|
+
"'".skip
|
98
|
+
node :single_quoted_string_literal,
|
99
|
+
:string_literal
|
100
|
+
production :single_quoted_string_literal
|
101
|
+
rule :single_quoted_string_content,
|
102
|
+
/(\\(?!').|\\'|[^'\\]+)+/
|
103
|
+
rule :double_quoted_string_literal,
|
104
|
+
'"'.skip &
|
105
|
+
:double_quoted_string_content.optional &
|
106
|
+
'"'.skip
|
107
|
+
node :double_quoted_string_literal, :string_literal
|
108
|
+
production :double_quoted_string_literal
|
109
|
+
rule :double_quoted_string_content,
|
110
|
+
/(\\(?!").|\\"|[^"\\]+)+/
|
111
|
+
|
112
|
+
# TODO: support 1_000_000 syntax for numeric_literals
|
113
|
+
rule :numeric_literal, /\d+\.\d+|\d+(?!\.)/
|
114
|
+
node :numeric_literal, :literal
|
115
|
+
production :numeric_literal
|
116
|
+
|
117
|
+
# this matches both "foo" and "Foo::bar"
|
118
|
+
rule :identifier, /([A-Z][a-zA-Z0-9_]*::)*[a-z_][a-zA-Z0-9_]*/
|
119
|
+
node :identifier, :literal
|
120
|
+
production :identifier
|
121
|
+
|
122
|
+
# this matches both "Foo" and "Foo::Bar"
|
123
|
+
rule :constant, /([A-Z][a-zA-Z0-9_]*::)*[A-Z][a-zA-Z0-9_]*/
|
124
|
+
node :constant, :literal
|
125
|
+
production :constant
|
126
|
+
|
127
|
+
rule :symbol_literal, /:[a-zA-Z_][a-zA-Z0-9_]*/
|
128
|
+
node :symbol_literal, :literal
|
129
|
+
production :symbol_literal
|
130
|
+
|
131
|
+
rule :escape_sequence, '\\'.skip & /[\$\\#]/
|
132
|
+
production :escape_sequence
|
133
|
+
|
134
|
+
rule :comment, '##'.skip & /.*$/
|
135
|
+
production :comment
|
136
|
+
|
137
|
+
# nested multiline comments
|
138
|
+
rule :multiline_comment, '#*'.skip & :comment_content.zero_or_more('') & '*#'.skip
|
139
|
+
skipping :multiline_comment, nil
|
140
|
+
production :multiline_comment, :content
|
141
|
+
|
142
|
+
rule :comment_content, (:comment & :newline.skip) |
|
143
|
+
:multiline_comment |
|
144
|
+
/( # three possibilities:
|
145
|
+
[^*#]+ | # 1. any run of characters other than # or *
|
146
|
+
\#(?!\#|\*) | # 2. any # not followed by another # or a *
|
147
|
+
\*(?!\#) # 3. any * not followed by a #
|
148
|
+
)+ # match the three possibilities repeatedly
|
149
|
+
/x
|
150
|
+
|
151
|
+
rule :directive, :block_directive |
|
152
|
+
:def_directive |
|
153
|
+
:echo_directive |
|
154
|
+
:extends_directive |
|
155
|
+
:import_directive |
|
156
|
+
:include_directive |
|
157
|
+
:raw_directive |
|
158
|
+
:ruby_directive |
|
159
|
+
:set_directive |
|
160
|
+
:silent_directive |
|
161
|
+
:slurp_directive |
|
162
|
+
:super_directive
|
163
|
+
|
164
|
+
node :directive
|
165
|
+
|
166
|
+
# directives may span multiple lines if and only if the last character on
|
167
|
+
# the line is a backslash \
|
168
|
+
skipping :directive, :whitespace | :line_continuation
|
169
|
+
|
170
|
+
# "Directive tags can be closed explicitly with #, or implicitly with the
|
171
|
+
# end of the line"
|
172
|
+
# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/language.directives.closures.html
|
173
|
+
# This means that to follow a directive by a comment on the same line you
|
174
|
+
# must explicitly close the directive first (otherwise the grammar would
|
175
|
+
# be ambiguous).
|
176
|
+
# Note that "skipping" the end_of_input here is harmless as it isn't
|
177
|
+
# actually consumed.
|
178
|
+
rule :directive_end, ( /#/ | :newline | :end_of_input ).skip
|
179
|
+
|
180
|
+
rule :block_directive, '#block'.skip & :identifier & :def_parameter_list.optional([]) & :directive_end &
|
181
|
+
:template_element.zero_or_more([]) &
|
182
|
+
'#end'.skip & :directive_end
|
183
|
+
production :block_directive, :identifier, :params, :content
|
184
|
+
|
185
|
+
rule :def_directive, '#def'.skip & :identifier & :def_parameter_list.optional([]) & :directive_end &
|
186
|
+
:template_element.zero_or_more([]) &
|
187
|
+
'#end'.skip & :directive_end
|
188
|
+
production :def_directive, :identifier, :params, :content
|
189
|
+
|
190
|
+
# "The #echo directive is used to echo the output from expressions that
|
191
|
+
# can't be written as simple $placeholders."
|
192
|
+
# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.echo.html
|
193
|
+
#
|
194
|
+
# Convenient alternative short syntax for the #echo directive, similar to
|
195
|
+
# ERB (http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/):
|
196
|
+
#
|
197
|
+
# #= expression(s) #
|
198
|
+
#
|
199
|
+
# Is a shortcut equivalent to:
|
200
|
+
#
|
201
|
+
# #echo expression(s) #
|
202
|
+
#
|
203
|
+
# This is similar to the ERB syntax, but even more concise:
|
204
|
+
#
|
205
|
+
# <%= expression(s) =>
|
206
|
+
#
|
207
|
+
# See also the #silent directive, which also has a shortcut syntax.
|
208
|
+
#
|
209
|
+
rule :echo_directive, '#echo'.skip & :ruby_expression_list & :directive_end | # long form
|
210
|
+
'#='.skip & :ruby_expression_list & '#'.skip # short form
|
211
|
+
production :echo_directive, :expression
|
212
|
+
|
213
|
+
rule :import_directive, '#import'.skip & :string_literal & :directive_end
|
214
|
+
production :import_directive, :class_name
|
215
|
+
|
216
|
+
rule :extends_directive, '#extends'.skip & :string_literal & :directive_end
|
217
|
+
node :extends_directive, :import_directive
|
218
|
+
production :extends_directive, :class_name
|
219
|
+
|
220
|
+
rule :include_directive, '#include'.skip & :include_subparslet
|
221
|
+
production :include_directive, :file_name, :subtree
|
222
|
+
|
223
|
+
rule :include_subparslet, lambda { |string, options|
|
224
|
+
|
225
|
+
# scans a string literal
|
226
|
+
parslet = :string_literal & :directive_end
|
227
|
+
file_name = parslet.parse(string, options)
|
228
|
+
|
229
|
+
# if options contains non-nil "origin" then try to construct relative
|
230
|
+
# path; otherwise just look in current working directory
|
231
|
+
if options[:origin]
|
232
|
+
current_location = Pathname.new(options[:origin]).dirname
|
233
|
+
include_target = current_location + file_name.to_s
|
81
234
|
else
|
82
|
-
|
83
|
-
self.class.const_get(parent_class.to_s.to_class_name.to_s).subclass(new_class_name, self.class, *attributes)
|
235
|
+
include_target = Pathname.new file_name.to_s
|
84
236
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
237
|
+
|
238
|
+
# read file into string
|
239
|
+
content = include_target.read
|
240
|
+
|
241
|
+
# try to parse string in sub-parser
|
242
|
+
sub_options = { :origin => include_target.to_s }
|
243
|
+
sub_result = nil
|
244
|
+
catch :AndPredicateSuccess do
|
245
|
+
sub_result = Parser.new.parse(content, sub_options)
|
246
|
+
end
|
247
|
+
|
248
|
+
# want to insert a bunch of nodes (a subtree) into the parse tree
|
249
|
+
# without advancing the location counters
|
250
|
+
sub_tree = Walrat::ArrayResult.new [ file_name, sub_result ? sub_result : [] ]
|
251
|
+
sub_tree.start = file_name.start
|
252
|
+
sub_tree.end = file_name.end
|
253
|
+
sub_tree
|
254
|
+
}
|
255
|
+
|
256
|
+
# "Any section of a template definition that is inside a #raw ... #end
|
257
|
+
# raw tag pair will be printed verbatim without any parsing of
|
258
|
+
# $placeholders or other directives."
|
259
|
+
# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.raw.html
|
260
|
+
# Unlike Cheetah, Walrus uses a bare "#end" marker and not an "#end raw"
|
261
|
+
# to mark the end of the raw block.
|
262
|
+
# The presence of a literal #end within a raw block is made possible by
|
263
|
+
# using an optional "here doc"-style delimiter:
|
264
|
+
#
|
265
|
+
# #raw <<END_MARKER
|
266
|
+
# content goes here
|
267
|
+
# END_MARKER
|
268
|
+
#
|
269
|
+
# Here the opening "END_MARKER" must be the last thing on the line
|
270
|
+
# (trailing whitespace up to and including the newline is allowed but it
|
271
|
+
# is not considered to be part of the quoted text). The final
|
272
|
+
# "END_MARKER" must be the very first and last thing on the line, or it
|
273
|
+
# will not be considered to be an end marker at all and will be
|
274
|
+
# considered part of the quoted text. The newline immediately prior to
|
275
|
+
# the end marker is included in the quoted text.
|
276
|
+
#
|
277
|
+
# Or, if the end marker is to be indented:
|
278
|
+
#
|
279
|
+
# #raw <<-END_MARKER
|
280
|
+
# content
|
281
|
+
# END_MARKER
|
282
|
+
#
|
283
|
+
# Here "END_MARKER" may be preceeded by whitespace (and whitespace only)
|
284
|
+
# but it must be the last thing on the line. The preceding whitespace is
|
285
|
+
# not considered to be part of the quoted text.
|
286
|
+
rule :raw_directive, '#raw'.skip &
|
287
|
+
((:directive_end & /([^#]+|#(?!end)+)*/ & '#end'.skip & :directive_end) | :here_document)
|
288
|
+
production :raw_directive, :content
|
289
|
+
|
290
|
+
# In order to parse "here documents" we adopt a model similar to the one
|
291
|
+
# proposed in this message to the ANTLR interest list:
|
292
|
+
# http://www.antlr.org:8080/pipermail/antlr-interest/2005-September/013673.html
|
293
|
+
rule :here_document, lambda { |string, options|
|
294
|
+
|
295
|
+
# for the time-being, not sure if there is much benefit in calling
|
296
|
+
# memoizing_parse here
|
297
|
+
state = Walrat::ParserState.new(string, options)
|
298
|
+
parsed = /<<(-?)([a-zA-Z0-9_]+)[ \t\v]*\n/.to_parseable.parse(state.remainder, state.options)
|
299
|
+
state.skipped(parsed)
|
300
|
+
marker = parsed.match_data
|
301
|
+
indenting = (marker[1] == '') ? false : true
|
302
|
+
|
303
|
+
if indenting # whitespace allowed before end marker
|
304
|
+
end_marker = /^[ \t\v]*#{marker[2]}[ \t\v]*(\n|\z)/.to_parseable # will eat trailing newline
|
305
|
+
else # no whitespace allowed before end marker
|
306
|
+
end_marker = /^#{marker[2]}[ \t\v]*(\n|\z)/.to_parseable # will eat trailing newline
|
137
307
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
#
|
151
|
-
# In the second mode of operation (when two parameters are passed) the rule_or_parslet parameter is interpreted to be the rule to which an override should be applied, where the parslet parameter specifies the parslet to be used in this case. If nil is explicitly passed then this overrides the default parslet; no parslet will be used for the purposes of inter-token skipping. Raises if an override has already been set for the named rule.
|
152
|
-
#
|
153
|
-
# The inter-token parslet is passed inside the "options" hash when invoking the "parse" methods. Any parser which fails will retry after giving this inter-token parslet a chance to consume and discard intervening whitespace.
|
154
|
-
# The initial, conservative implementation only performs this fallback skipping for ParsletSequence and ParsletRepetition combinations.
|
155
|
-
#
|
156
|
-
# Raises if rule_or_parslet is nil.
|
157
|
-
def skipping(rule_or_parslet, parslet = NoParameterMarker.instance)
|
158
|
-
raise ArgumentError if rule_or_parslet.nil?
|
159
|
-
if parslet == NoParameterMarker.instance # first mode of operation: set default parslet
|
160
|
-
raise if @skipping # should not set a default skipping parslet twice
|
161
|
-
@skipping = rule_or_parslet
|
162
|
-
else # second mode of operation: override default case
|
163
|
-
raise ArgumentError if @skipping_overrides.has_key?(rule_or_parslet)
|
164
|
-
raise ArgumentError unless @rules.has_key?(rule_or_parslet)
|
165
|
-
@skipping_overrides[rule_or_parslet] = parslet
|
308
|
+
|
309
|
+
line = /^.*\n/.to_parseable # for gobbling a line
|
310
|
+
|
311
|
+
while true do
|
312
|
+
begin
|
313
|
+
skipped = end_marker.parse(state.remainder, state.options)
|
314
|
+
state.skipped(skipped) # found end marker, skip it
|
315
|
+
break # all done
|
316
|
+
rescue Walrat::ParseError # didn't find end marker yet, consume a line
|
317
|
+
parsed = line.parse(state.remainder, state.options)
|
318
|
+
state.parsed(parsed)
|
319
|
+
end
|
166
320
|
end
|
167
|
-
end
|
168
|
-
|
169
|
-
# TODO: pretty print method?
|
170
|
-
|
171
|
-
end # class Grammar
|
172
|
-
end # module Walrus
|
173
321
|
|
322
|
+
# caller will want a String, not an Array
|
323
|
+
results = state.results
|
324
|
+
document = Walrat::StringResult.new(results.to_s)
|
325
|
+
document.start = results.start
|
326
|
+
document.end = results.end
|
327
|
+
document
|
328
|
+
}
|
329
|
+
|
330
|
+
rule :ruby_directive, '#ruby'.skip & ((:directive_end & /([^#]+|#(?!end)+)*/ & '#end'.skip & :directive_end) | :here_document)
|
331
|
+
production :ruby_directive, :content
|
332
|
+
|
333
|
+
# Unlike a normal Ruby assignement expression, the lvalue of a "#set"
|
334
|
+
# directive is an identifier preceded by a dollar sign.
|
335
|
+
rule :set_directive, '#set'.skip & /\$(?![ \r\n\t\v])/.skip & :placeholder_name & '='.skip & (:addition_expression | :unary_expression) & :directive_end
|
336
|
+
production :set_directive, :placeholder, :expression
|
337
|
+
|
338
|
+
# "#silent is the opposite of #echo. It executes an expression but
|
339
|
+
# discards the output."
|
340
|
+
# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.silent.html
|
341
|
+
#
|
342
|
+
# Like the #echo directive, a convienient shorthand syntax is available:
|
343
|
+
#
|
344
|
+
# # expressions(s) #
|
345
|
+
#
|
346
|
+
# Equivalent to the long form:
|
347
|
+
#
|
348
|
+
# #silent expressions(s) #
|
349
|
+
#
|
350
|
+
# And similar to but more concise than the ERB syntax:
|
351
|
+
#
|
352
|
+
# <% expressions(s) %>
|
353
|
+
#
|
354
|
+
# Note that the space between the opening hash character and the
|
355
|
+
# expression(s) is required in order for Walrus to distinguish the
|
356
|
+
# shorthand for the #silent directive from the other directives. That is,
|
357
|
+
# the following is not legal:
|
358
|
+
#
|
359
|
+
# #expressions(s) #
|
360
|
+
#
|
361
|
+
rule :silent_directive, '#silent'.skip & :ruby_expression_list & :directive_end | # long form
|
362
|
+
'# '.skip & :ruby_expression_list & '#'.skip # short form
|
363
|
+
production :silent_directive, :expression
|
364
|
+
|
365
|
+
# Accept multiple expressions separated by a semi-colon.
|
366
|
+
rule :ruby_expression_list, :ruby_expression >> (';'.skip & :ruby_expression ).zero_or_more
|
367
|
+
|
368
|
+
# "The #slurp directive eats up the trailing newline on the line it
|
369
|
+
# appears in, joining the following line onto the current line."
|
370
|
+
# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/output.slurp.html
|
371
|
+
# The "slurp" directive must be the last thing on the line (not followed
|
372
|
+
# by a comment or directive end marker)
|
373
|
+
rule :slurp_directive, '#slurp' & :whitespace.optional.skip & :newline.skip
|
374
|
+
production :slurp_directive
|
174
375
|
|
376
|
+
rule :super_directive, :super_with_parentheses | :super_without_parentheses
|
377
|
+
rule :super_with_parentheses, '#super'.skip & :parameter_list.optional & :directive_end
|
378
|
+
node :super_with_parentheses, :super_directive
|
379
|
+
production :super_with_parentheses, :params
|
380
|
+
rule :super_without_parentheses, '#super'.skip & :parameter_list_without_parentheses & :directive_end
|
381
|
+
node :super_without_parentheses, :super_directive
|
382
|
+
production :super_without_parentheses, :params
|
175
383
|
|
384
|
+
# The "def_parameter_list" is a special case of parameter list which
|
385
|
+
# disallows interpolated placeholders.
|
386
|
+
rule :def_parameter_list, '('.skip & ( :def_parameter >> ( ','.skip & :def_parameter ).zero_or_more ).optional & ')'.skip
|
387
|
+
rule :def_parameter, :assignment_expression | :identifier
|
176
388
|
|
389
|
+
rule :parameter_list, '('.skip & ( :parameter >> ( ','.skip & :parameter ).zero_or_more ).optional & ')'.skip
|
390
|
+
rule :parameter_list_without_parentheses, :parameter >> ( ','.skip & :parameter ).zero_or_more
|
391
|
+
rule :parameter, :placeholder | :ruby_expression
|
392
|
+
|
393
|
+
# placeholders may be in long form (${foo}) or short form ($foo)
|
394
|
+
rule :placeholder, :long_placeholder | :short_placeholder
|
395
|
+
|
396
|
+
# No whitespace allowed between the "$" and the opening "{"
|
397
|
+
rule :long_placeholder, '${'.skip & :placeholder_name & :placeholder_parameters.optional([]) & '}'.skip
|
398
|
+
node :long_placeholder, :placeholder
|
399
|
+
production :long_placeholder, :name, :params
|
400
|
+
|
401
|
+
# No whitespace allowed between the "$" and the placeholder_name
|
402
|
+
rule :short_placeholder, /\$(?![ \r\n\t\v])/.skip & :placeholder_name & :placeholder_parameters.optional([])
|
403
|
+
node :short_placeholder, :placeholder
|
404
|
+
production :short_placeholder, :name, :params
|
405
|
+
|
406
|
+
rule :placeholder_name, :identifier
|
407
|
+
rule :placeholder_parameters, '('.skip & (:placeholder_parameter >> (','.skip & :placeholder_parameter).zero_or_more).optional & ')'.skip
|
408
|
+
rule :placeholder_parameter, :placeholder | :ruby_expression
|
409
|
+
|
410
|
+
# simplified Ruby subset
|
411
|
+
rule :ruby_expression, :assignment_expression | :addition_expression | :unary_expression
|
412
|
+
|
413
|
+
rule :literal_expression, :string_literal |
|
414
|
+
:numeric_literal |
|
415
|
+
:array_literal |
|
416
|
+
:hash_literal |
|
417
|
+
:lvalue |
|
418
|
+
:symbol_literal
|
419
|
+
rule :unary_expression, :message_expression | :literal_expression
|
420
|
+
|
421
|
+
rule :lvalue, :class_variable | :instance_variable | :identifier | :constant
|
422
|
+
|
423
|
+
rule :array_literal, '['.skip & ( :ruby_expression >> (','.skip & :ruby_expression ).zero_or_more ).optional & ']'.skip
|
424
|
+
node :array_literal, :ruby_expression
|
425
|
+
production :array_literal, :elements
|
426
|
+
|
427
|
+
rule :hash_literal, '{'.skip & ( :hash_assignment >> (','.skip & :hash_assignment ).zero_or_more ).optional & '}'.skip
|
428
|
+
node :hash_literal, :ruby_expression
|
429
|
+
production :hash_literal, :pairs
|
430
|
+
|
431
|
+
rule :hash_assignment, :unary_expression & '=>'.skip & (:addition_expression | :unary_expression)
|
432
|
+
node :hash_assignment, :ruby_expression
|
433
|
+
production :hash_assignment, :lvalue, :expression
|
434
|
+
|
435
|
+
rule :assignment_expression, :lvalue & '='.skip & (:addition_expression | :unary_expression)
|
436
|
+
production :assignment_expression, :lvalue, :expression
|
437
|
+
|
438
|
+
# addition is left-associative (left-recursive)
|
439
|
+
rule :addition_expression, :addition_expression & '+'.skip & :unary_expression |
|
440
|
+
:unary_expression & '+'.skip & :unary_expression
|
441
|
+
|
442
|
+
node :addition_expression, :ruby_expression
|
443
|
+
production :addition_expression, :left, :right
|
444
|
+
|
445
|
+
# message expressions are left-associative (left-recursive)
|
446
|
+
rule :message_expression,
|
447
|
+
:message_expression & '.'.skip & :method_expression |
|
448
|
+
:literal_expression & '.'.skip & :method_expression
|
449
|
+
production :message_expression, :target, :message
|
450
|
+
|
451
|
+
rule :method_expression,
|
452
|
+
:method_with_parentheses | :method_without_parentheses
|
453
|
+
node :method_expression, :ruby_expression
|
454
|
+
|
455
|
+
rule :method_with_parentheses,
|
456
|
+
:identifier & :method_parameter_list.optional([])
|
457
|
+
node :method_with_parentheses, :method_expression
|
458
|
+
production :method_with_parentheses, :name, :params
|
459
|
+
rule :method_without_parentheses,
|
460
|
+
:identifier & :method_parameter_list_without_parentheses
|
461
|
+
node :method_without_parentheses, :method_expression
|
462
|
+
production :method_without_parentheses, :method_expression, :name, :params
|
463
|
+
|
464
|
+
rule :method_parameter_list,
|
465
|
+
'('.skip & ( :method_parameter >> ( ','.skip & :method_parameter ).zero_or_more ).optional & ')'.skip
|
466
|
+
rule :method_parameter,
|
467
|
+
:ruby_expression
|
468
|
+
rule :method_parameter_list_without_parentheses,
|
469
|
+
:method_parameter >> ( ','.skip & :method_parameter ).zero_or_more
|
470
|
+
|
471
|
+
rule :class_variable, '@@'.skip & :identifier
|
472
|
+
skipping :class_variable, nil
|
473
|
+
node :class_variable, :ruby_expression
|
474
|
+
production :class_variable
|
475
|
+
|
476
|
+
rule :instance_variable, '@'.skip & :identifier
|
477
|
+
skipping :instance_variable, nil
|
478
|
+
production :instance_variable
|
479
|
+
|
480
|
+
# TODO: regexp literal expression
|
481
|
+
|
482
|
+
# Ruby + allowing placeholders for unary expressions
|
483
|
+
rule :extended_ruby_expression,
|
484
|
+
:extended_unary_expression | :ruby_expression
|
485
|
+
rule :extended_unary_expression,
|
486
|
+
:placeholder | :unary_expression
|
487
|
+
end # class Grammar
|
488
|
+
end # module Walrus
|