walrus 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/walrus +44 -0
- data/ext/jindex/extconf.rb +11 -0
- data/ext/jindex/jindex.c +79 -0
- data/ext/mkdtemp/extconf.rb +11 -0
- data/ext/mkdtemp/mkdtemp.c +41 -0
- data/lib/walrus/additions/module.rb +36 -0
- data/lib/walrus/additions/string.rb +37 -0
- data/lib/walrus/additions/test/unit/error_collector.rb +62 -0
- data/lib/walrus/compile_error.rb +28 -0
- data/lib/walrus/compiler.rb +124 -0
- data/lib/walrus/contrib/spec/walruscloth_spec.rb +32 -0
- data/lib/walrus/contrib/walruscloth.rb +82 -0
- data/lib/walrus/diff.rb +89 -0
- data/lib/walrus/document.rb +98 -0
- data/lib/walrus/grammar/additions/proc.rb +20 -0
- data/lib/walrus/grammar/additions/regexp.rb +21 -0
- data/lib/walrus/grammar/additions/string.rb +52 -0
- data/lib/walrus/grammar/additions/symbol.rb +42 -0
- data/lib/walrus/grammar/and_predicate.rb +40 -0
- data/lib/walrus/grammar/array_result.rb +19 -0
- data/lib/walrus/grammar/continuation_wrapper_exception.rb +28 -0
- data/lib/walrus/grammar/left_recursion_exception.rb +27 -0
- data/lib/walrus/grammar/location_tracking.rb +105 -0
- data/lib/walrus/grammar/match_data_wrapper.rb +65 -0
- data/lib/walrus/grammar/memoizing.rb +41 -0
- data/lib/walrus/grammar/memoizing_cache.rb +94 -0
- data/lib/walrus/grammar/node.rb +60 -0
- data/lib/walrus/grammar/not_predicate.rb +40 -0
- data/lib/walrus/grammar/parse_error.rb +39 -0
- data/lib/walrus/grammar/parser_state.rb +181 -0
- data/lib/walrus/grammar/parslet.rb +28 -0
- data/lib/walrus/grammar/parslet_choice.rb +120 -0
- data/lib/walrus/grammar/parslet_combination.rb +26 -0
- data/lib/walrus/grammar/parslet_combining.rb +154 -0
- data/lib/walrus/grammar/parslet_merge.rb +88 -0
- data/lib/walrus/grammar/parslet_omission.rb +57 -0
- data/lib/walrus/grammar/parslet_repetition.rb +97 -0
- data/lib/walrus/grammar/parslet_repetition_default.rb +58 -0
- data/lib/walrus/grammar/parslet_sequence.rb +202 -0
- data/lib/walrus/grammar/predicate.rb +57 -0
- data/lib/walrus/grammar/proc_parslet.rb +52 -0
- data/lib/walrus/grammar/regexp_parslet.rb +73 -0
- data/lib/walrus/grammar/skipped_substring_exception.rb +36 -0
- data/lib/walrus/grammar/string_enumerator.rb +45 -0
- data/lib/walrus/grammar/string_parslet.rb +75 -0
- data/lib/walrus/grammar/string_result.rb +24 -0
- data/lib/walrus/grammar/symbol_parslet.rb +63 -0
- data/lib/walrus/grammar.rb +170 -0
- data/lib/walrus/no_parameter_marker.rb +19 -0
- data/lib/walrus/parser.rb +420 -0
- data/lib/walrus/runner.rb +356 -0
- data/lib/walrus/template.rb +75 -0
- data/lib/walrus/walrus_grammar/assignment_expression.rb +24 -0
- data/lib/walrus/walrus_grammar/block_directive.rb +28 -0
- data/lib/walrus/walrus_grammar/comment.rb +24 -0
- data/lib/walrus/walrus_grammar/def_directive.rb +64 -0
- data/lib/walrus/walrus_grammar/echo_directive.rb +44 -0
- data/lib/walrus/walrus_grammar/escape_sequence.rb +24 -0
- data/lib/walrus/walrus_grammar/import_directive.rb +44 -0
- data/lib/walrus/walrus_grammar/include_directive.rb +27 -0
- data/lib/walrus/walrus_grammar/instance_variable.rb +24 -0
- data/lib/walrus/walrus_grammar/literal.rb +24 -0
- data/lib/walrus/walrus_grammar/message_expression.rb +25 -0
- data/lib/walrus/walrus_grammar/multiline_comment.rb +54 -0
- data/lib/walrus/walrus_grammar/placeholder.rb +40 -0
- data/lib/walrus/walrus_grammar/raw_directive.rb +42 -0
- data/lib/walrus/walrus_grammar/raw_text.rb +45 -0
- data/lib/walrus/walrus_grammar/ruby_directive.rb +29 -0
- data/lib/walrus/walrus_grammar/ruby_expression.rb +31 -0
- data/lib/walrus/walrus_grammar/set_directive.rb +24 -0
- data/lib/walrus/walrus_grammar/silent_directive.rb +44 -0
- data/lib/walrus/walrus_grammar/slurp_directive.rb +25 -0
- data/lib/walrus/walrus_grammar/super_directive.rb +27 -0
- data/lib/walrus.rb +64 -0
- data/spec/acceptance/acceptance_spec.rb +97 -0
- data/spec/acceptance/block/basic_block.expected +1 -0
- data/spec/acceptance/block/basic_block.tmpl +3 -0
- data/spec/acceptance/block/nested_blocks.expected +5 -0
- data/spec/acceptance/block/nested_blocks.tmpl +11 -0
- data/spec/acceptance/comments/comments_and_text.expected +3 -0
- data/spec/acceptance/comments/comments_and_text.tmpl +6 -0
- data/spec/acceptance/comments/single_comment.expected +0 -0
- data/spec/acceptance/comments/single_comment.tmpl +1 -0
- data/spec/acceptance/def/alternative_def_calling_conventions.expected +3 -0
- data/spec/acceptance/def/alternative_def_calling_conventions.tmpl +18 -0
- data/spec/acceptance/def/basic_def_block_no_output.expected +0 -0
- data/spec/acceptance/def/basic_def_block_no_output.tmpl +17 -0
- data/spec/acceptance/def/defs_can_be_called_multiple_times.expected +3 -0
- data/spec/acceptance/def/defs_can_be_called_multiple_times.tmpl +6 -0
- data/spec/acceptance/def/defs_can_be_dynamic.expected +4 -0
- data/spec/acceptance/def/defs_can_be_dynamic.tmpl +12 -0
- data/spec/acceptance/echo/echo_directive_with_numeric_literal.expected +1 -0
- data/spec/acceptance/echo/echo_directive_with_numeric_literal.tmpl +1 -0
- data/spec/acceptance/echo/echo_expression_list.expected +1 -0
- data/spec/acceptance/echo/echo_expression_list.tmpl +1 -0
- data/spec/acceptance/echo/echo_short_notation.expected +1 -0
- data/spec/acceptance/echo/echo_short_notation.tmpl +1 -0
- data/spec/acceptance/echo/echo_simple_expression.expected +1 -0
- data/spec/acceptance/echo/echo_simple_expression.tmpl +1 -0
- data/spec/acceptance/echo/echo_single_quoted_string_literal.expected +1 -0
- data/spec/acceptance/echo/echo_single_quoted_string_literal.tmpl +1 -0
- data/spec/acceptance/echo/multiple_echo_statements.expected +1 -0
- data/spec/acceptance/echo/multiple_echo_statements.tmpl +2 -0
- data/spec/acceptance/includes/basic_included_file.txt +1 -0
- data/spec/acceptance/includes/basic_includer.complex +3 -0
- data/spec/acceptance/includes/basic_includer.expected +3 -0
- data/spec/acceptance/includes/basic_includer.rb +38 -0
- data/spec/acceptance/includes/complicated_included_file.txt +3 -0
- data/spec/acceptance/includes/complicated_includer.complex +3 -0
- data/spec/acceptance/includes/complicated_includer.expected +3 -0
- data/spec/acceptance/includes/complicated_includer.rb +41 -0
- data/spec/acceptance/includes/nested_include_1.txt +3 -0
- data/spec/acceptance/includes/nested_include_2.txt +1 -0
- data/spec/acceptance/includes/nested_includer.complex +3 -0
- data/spec/acceptance/includes/nested_includer.expected +4 -0
- data/spec/acceptance/includes/nested_includer.rb +41 -0
- data/spec/acceptance/inheritance/basic_child.complex +10 -0
- data/spec/acceptance/inheritance/basic_child.expected +9 -0
- data/spec/acceptance/inheritance/basic_child.rb +54 -0
- data/spec/acceptance/inheritance/basic_parent.complex +5 -0
- data/spec/acceptance/inheritance/basic_parent.expected +3 -0
- data/spec/acceptance/inheritance/basic_parent.rb +41 -0
- data/spec/acceptance/inheritance/importing_child.complex +8 -0
- data/spec/acceptance/inheritance/importing_child.expected +7 -0
- data/spec/acceptance/inheritance/importing_child.rb +46 -0
- data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.complex +8 -0
- data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.expected +7 -0
- data/spec/acceptance/inheritance/subdirectory/importing_child_in_subdirectory.rb +44 -0
- data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.expected +0 -0
- data/spec/acceptance/multiline_comments/multiline_comment_with_directives_inside.tmpl +15 -0
- data/spec/acceptance/multiline_comments/simple_multiline_comment.expected +2 -0
- data/spec/acceptance/multiline_comments/simple_multiline_comment.tmpl +4 -0
- data/spec/acceptance/raw/complicated_raw_example.expected +57 -0
- data/spec/acceptance/raw/complicated_raw_example.tmpl +79 -0
- data/spec/acceptance/raw-text/UTF_8.expected +12 -0
- data/spec/acceptance/raw-text/UTF_8.tmpl +12 -0
- data/spec/acceptance/raw-text/empty_file.expected +0 -0
- data/spec/acceptance/raw-text/empty_file.tmpl +0 -0
- data/spec/acceptance/raw-text/multi_line.expected +4 -0
- data/spec/acceptance/raw-text/multi_line.tmpl +4 -0
- data/spec/acceptance/raw-text/single_line.expected +1 -0
- data/spec/acceptance/raw-text/single_line.tmpl +1 -0
- data/spec/acceptance/raw-text/single_line_whitespace.expected +1 -0
- data/spec/acceptance/raw-text/single_line_whitespace.tmpl +1 -0
- data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.expected +1 -0
- data/spec/acceptance/ruby/ruby_directive_is_just_like_silent.tmpl +4 -0
- data/spec/acceptance/ruby/ruby_directive_using_here_doc.expected +1 -0
- data/spec/acceptance/ruby/ruby_directive_using_here_doc.tmpl +4 -0
- data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.expected +1 -0
- data/spec/acceptance/ruby/ruby_directive_using_here_doc_alt_syntax.tmpl +4 -0
- data/spec/acceptance/ruby/ruby_directive_with_accumulate.expected +1 -0
- data/spec/acceptance/ruby/ruby_directive_with_accumulate.tmpl +4 -0
- data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.expected +1 -0
- data/spec/acceptance/ruby/ruby_directive_with_accumulate_and_block.tmpl +6 -0
- data/spec/acceptance/set/unused_set.expected +0 -0
- data/spec/acceptance/set/unused_set.tmpl +1 -0
- data/spec/acceptance/set/used_set.expected +1 -0
- data/spec/acceptance/set/used_set.tmpl +2 -0
- data/spec/acceptance/silent/silent_and_echo_combined.expected +1 -0
- data/spec/acceptance/silent/silent_and_echo_combined.tmpl +2 -0
- data/spec/acceptance/silent/silent_short_notation.expected +1 -0
- data/spec/acceptance/silent/silent_short_notation.tmpl +1 -0
- data/spec/acceptance/silent/simple_silent_directive.expected +0 -0
- data/spec/acceptance/silent/simple_silent_directive.tmpl +1 -0
- data/spec/acceptance/slurp/basic_slurp_demo.expected +1 -0
- data/spec/acceptance/slurp/basic_slurp_demo.tmpl +4 -0
- data/spec/acceptance/super/super_with_no_effect.expected +4 -0
- data/spec/acceptance/super/super_with_no_effect.tmpl +5 -0
- data/spec/additions/module_spec.rb +126 -0
- data/spec/additions/string_spec.rb +99 -0
- data/spec/compiler_spec.rb +55 -0
- data/spec/grammar/additions/proc_spec.rb +25 -0
- data/spec/grammar/additions/regexp_spec.rb +37 -0
- data/spec/grammar/additions/string_spec.rb +106 -0
- data/spec/grammar/and_predicate_spec.rb +29 -0
- data/spec/grammar/continuation_wrapper_exception_spec.rb +23 -0
- data/spec/grammar/match_data_wrapper_spec.rb +41 -0
- data/spec/grammar/memoizing_cache_spec.rb +112 -0
- data/spec/grammar/node_spec.rb +126 -0
- data/spec/grammar/not_predicate_spec.rb +29 -0
- data/spec/grammar/parser_state_spec.rb +172 -0
- data/spec/grammar/parslet_choice_spec.rb +49 -0
- data/spec/grammar/parslet_combining_spec.rb +287 -0
- data/spec/grammar/parslet_merge_spec.rb +33 -0
- data/spec/grammar/parslet_omission_spec.rb +58 -0
- data/spec/grammar/parslet_repetition_spec.rb +77 -0
- data/spec/grammar/parslet_sequence_spec.rb +49 -0
- data/spec/grammar/parslet_spec.rb +23 -0
- data/spec/grammar/predicate_spec.rb +53 -0
- data/spec/grammar/proc_parslet_spec.rb +52 -0
- data/spec/grammar/regexp_parslet_spec.rb +347 -0
- data/spec/grammar/string_enumerator_spec.rb +94 -0
- data/spec/grammar/string_parslet_spec.rb +143 -0
- data/spec/grammar/symbol_parslet_spec.rb +30 -0
- data/spec/grammar_spec.rb +545 -0
- data/spec/parser_spec.rb +1418 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/walrus_grammar/comment_spec.rb +39 -0
- data/spec/walrus_grammar/echo_directive_spec.rb +63 -0
- data/spec/walrus_grammar/escape_sequence_spec.rb +85 -0
- data/spec/walrus_grammar/literal_spec.rb +41 -0
- data/spec/walrus_grammar/message_expression_spec.rb +37 -0
- data/spec/walrus_grammar/multiline_comment_spec.rb +58 -0
- data/spec/walrus_grammar/placeholder_spec.rb +48 -0
- data/spec/walrus_grammar/raw_directive_spec.rb +81 -0
- data/spec/walrus_grammar/raw_text_spec.rb +65 -0
- data/spec/walrus_grammar/silent_directive_spec.rb +34 -0
- metadata +291 -0
data/lib/walrus/diff.rb
ADDED
@@ -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
|
+
|