walrus 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -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: /mirrors/Walrus/trunk/walrus/spec/grammar/proc_parslet_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
10
|
+
|
|
11
|
+
module Walrus
|
|
12
|
+
class Grammar
|
|
13
|
+
|
|
14
|
+
describe 'using a ProcParslet' do
|
|
15
|
+
|
|
16
|
+
setup do
|
|
17
|
+
@parslet = lambda do |string, options|
|
|
18
|
+
if string == 'foobar' : string
|
|
19
|
+
else raise ParseError.new('expected foobar by got "%s"' + string.to_s)
|
|
20
|
+
end
|
|
21
|
+
end.to_parseable
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should raise an ArgumentError if initialized with nil' do
|
|
25
|
+
lambda { ProcParslet.new(nil) }.should raise_error(ArgumentError)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should complain if asked to parse nil' do
|
|
29
|
+
lambda { @parslet.parse(nil) }.should raise_error(ArgumentError)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'should raise ParseError if unable to parse' do
|
|
33
|
+
lambda { @parslet.parse('bar') }.should raise_error(ParseError)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'should return a parsed value if able to parse' do
|
|
37
|
+
@parslet.parse('foobar').should == 'foobar'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'should be able to compare parslets for equality' do
|
|
41
|
+
|
|
42
|
+
# in practice only parslets created with the exact same Proc instance will be eql because Proc returns different hashes for each
|
|
43
|
+
@parslet.should eql(@parslet.clone)
|
|
44
|
+
@parslet.should eql(@parslet.dup)
|
|
45
|
+
@parslet.should_not eql(lambda { nil }.to_parseable)
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end # class Grammar
|
|
52
|
+
end # module Walrus
|
|
@@ -0,0 +1,347 @@
|
|
|
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/spec/grammar/regexp_parslet_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
10
|
+
|
|
11
|
+
module Walrus
|
|
12
|
+
class Grammar
|
|
13
|
+
|
|
14
|
+
describe 'using a regexp parslet' do
|
|
15
|
+
|
|
16
|
+
setup do
|
|
17
|
+
@parslet = RegexpParslet.new(/[a-zA-Z_][a-zA-Z0-9_]*/)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should raise an ArgumentError if initialized with nil' do
|
|
21
|
+
lambda { RegexpParslet.new(nil) }.should raise_error(ArgumentError)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'parse should succeed if the input string matches' do
|
|
25
|
+
lambda { @parslet.parse('an_identifier') }.should_not raise_error
|
|
26
|
+
lambda { @parslet.parse('An_Identifier') }.should_not raise_error
|
|
27
|
+
lambda { @parslet.parse('AN_IDENTIFIER') }.should_not raise_error
|
|
28
|
+
lambda { @parslet.parse('an_identifier1') }.should_not raise_error
|
|
29
|
+
lambda { @parslet.parse('An_Identifier1') }.should_not raise_error
|
|
30
|
+
lambda { @parslet.parse('AN_IDENTIFIER1') }.should_not raise_error
|
|
31
|
+
lambda { @parslet.parse('a') }.should_not raise_error
|
|
32
|
+
lambda { @parslet.parse('A') }.should_not raise_error
|
|
33
|
+
lambda { @parslet.parse('a9') }.should_not raise_error
|
|
34
|
+
lambda { @parslet.parse('A9') }.should_not raise_error
|
|
35
|
+
lambda { @parslet.parse('_identifier') }.should_not raise_error
|
|
36
|
+
lambda { @parslet.parse('_Identifier') }.should_not raise_error
|
|
37
|
+
lambda { @parslet.parse('_IDENTIFIER') }.should_not raise_error
|
|
38
|
+
lambda { @parslet.parse('_9Identifier') }.should_not raise_error
|
|
39
|
+
lambda { @parslet.parse('_') }.should_not raise_error
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'parse should succeed if the input string matches, even if it continues after the match' do
|
|
43
|
+
lambda { @parslet.parse('an_identifier, more') }.should_not raise_error
|
|
44
|
+
lambda { @parslet.parse('An_Identifier, more') }.should_not raise_error
|
|
45
|
+
lambda { @parslet.parse('AN_IDENTIFIER, more') }.should_not raise_error
|
|
46
|
+
lambda { @parslet.parse('an_identifier1, more') }.should_not raise_error
|
|
47
|
+
lambda { @parslet.parse('An_Identifier1, more') }.should_not raise_error
|
|
48
|
+
lambda { @parslet.parse('AN_IDENTIFIER1, more') }.should_not raise_error
|
|
49
|
+
lambda { @parslet.parse('a, more') }.should_not raise_error
|
|
50
|
+
lambda { @parslet.parse('A, more') }.should_not raise_error
|
|
51
|
+
lambda { @parslet.parse('a9, more') }.should_not raise_error
|
|
52
|
+
lambda { @parslet.parse('A9, more') }.should_not raise_error
|
|
53
|
+
lambda { @parslet.parse('_identifier, more') }.should_not raise_error
|
|
54
|
+
lambda { @parslet.parse('_Identifier, more') }.should_not raise_error
|
|
55
|
+
lambda { @parslet.parse('_IDENTIFIER, more') }.should_not raise_error
|
|
56
|
+
lambda { @parslet.parse('_9Identifier, more') }.should_not raise_error
|
|
57
|
+
lambda { @parslet.parse('_, more') }.should_not raise_error
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'parse should return a MatchDataWrapper object' do
|
|
61
|
+
@parslet.parse('an_identifier').should == 'an_identifier'
|
|
62
|
+
@parslet.parse('an_identifier, more').should == 'an_identifier'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'parse should raise an ArgumentError if passed nil' do
|
|
66
|
+
lambda { @parslet.parse(nil) }.should raise_error(ArgumentError)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'parse should raise a ParseError if the input string does not match' do
|
|
70
|
+
lambda { @parslet.parse('9') }.should raise_error(ParseError) # a number is not a valid identifier
|
|
71
|
+
lambda { @parslet.parse('9fff') }.should raise_error(ParseError) # identifiers must not start with numbers
|
|
72
|
+
lambda { @parslet.parse(' identifier') }.should raise_error(ParseError) # note the leading whitespace
|
|
73
|
+
lambda { @parslet.parse('') }.should raise_error(ParseError) # empty strings can't match
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should be able to compare parslets for equality' do
|
|
77
|
+
/foo/.to_parseable.should eql(/foo/.to_parseable) # equal
|
|
78
|
+
/foo/.to_parseable.should_not eql(/bar/.to_parseable) # different
|
|
79
|
+
/foo/.to_parseable.should_not eql(/Foo/.to_parseable) # differing only in case
|
|
80
|
+
/foo/.to_parseable.should_not eql('foo') # totally different classes
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'should accurately pack line and column ends into whatever gets returned from "parse"' do
|
|
84
|
+
|
|
85
|
+
# single word
|
|
86
|
+
parslet = /.+/m.to_parseable
|
|
87
|
+
result = parslet.parse('hello')
|
|
88
|
+
result.line_end.should == 0
|
|
89
|
+
result.column_end.should == 5
|
|
90
|
+
|
|
91
|
+
# single word with newline at end (UNIX style)
|
|
92
|
+
result = parslet.parse("hello\n")
|
|
93
|
+
result.line_end.should == 1
|
|
94
|
+
result.column_end.should == 0
|
|
95
|
+
|
|
96
|
+
# single word with newline at end (Classic Mac style)
|
|
97
|
+
result = parslet.parse("hello\r")
|
|
98
|
+
result.line_end.should == 1
|
|
99
|
+
result.column_end.should == 0
|
|
100
|
+
|
|
101
|
+
# single word with newline at end (Windows style)
|
|
102
|
+
result = parslet.parse("hello\r\n")
|
|
103
|
+
result.line_end.should == 1
|
|
104
|
+
result.column_end.should == 0
|
|
105
|
+
|
|
106
|
+
# two lines (UNIX style)
|
|
107
|
+
result = parslet.parse("hello\nworld")
|
|
108
|
+
result.line_end.should == 1
|
|
109
|
+
result.column_end.should == 5
|
|
110
|
+
|
|
111
|
+
# two lines (Classic Mac style)
|
|
112
|
+
result = parslet.parse("hello\rworld")
|
|
113
|
+
result.line_end.should == 1
|
|
114
|
+
result.column_end.should == 5
|
|
115
|
+
|
|
116
|
+
# two lines (Windows style)
|
|
117
|
+
result = parslet.parse("hello\r\nworld")
|
|
118
|
+
result.line_end.should == 1
|
|
119
|
+
result.column_end.should == 5
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# in the case of RegexpParslets, the "last successfully scanned position" is always 0, 0
|
|
124
|
+
it 'line and column end should reflect last succesfully scanned position prior to failure' do
|
|
125
|
+
|
|
126
|
+
# fail right at start
|
|
127
|
+
parslet = /hello\r\nworld/.to_parseable
|
|
128
|
+
begin
|
|
129
|
+
parslet.parse('foobar')
|
|
130
|
+
rescue ParseError => e
|
|
131
|
+
exception = e
|
|
132
|
+
end
|
|
133
|
+
exception.line_end.should == 0
|
|
134
|
+
exception.column_end.should == 0
|
|
135
|
+
|
|
136
|
+
# fail after 1 character
|
|
137
|
+
begin
|
|
138
|
+
parslet.parse('hfoobar')
|
|
139
|
+
rescue ParseError => e
|
|
140
|
+
exception = e
|
|
141
|
+
end
|
|
142
|
+
exception.line_end.should == 0
|
|
143
|
+
exception.column_end.should == 0
|
|
144
|
+
|
|
145
|
+
# fail after end-of-line
|
|
146
|
+
begin
|
|
147
|
+
parslet.parse("hello\r\nfoobar")
|
|
148
|
+
rescue ParseError => e
|
|
149
|
+
exception = e
|
|
150
|
+
end
|
|
151
|
+
exception.line_end.should == 0
|
|
152
|
+
exception.column_end.should == 0
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe 'chaining two regexp parslets together' do
|
|
159
|
+
|
|
160
|
+
it 'parslets should work in specified order' do
|
|
161
|
+
parslet = RegexpParslet.new(/foo.\d/) & RegexpParslet.new(/bar.\d/)
|
|
162
|
+
parslet.parse('foo_1bar_2').should == ['foo_1', 'bar_2']
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Parser Expression Grammars match greedily
|
|
166
|
+
it 'parslets should match greedily' do
|
|
167
|
+
|
|
168
|
+
# the first parslet should gobble up the entire string, preventing the second parslet from succeeding
|
|
169
|
+
parslet = RegexpParslet.new(/foo.+\d/) & RegexpParslet.new(/bar.+\d/)
|
|
170
|
+
lambda { parslet.parse('foo_1bar_2') }.should raise_error(ParseError)
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
describe 'alternating two regexp parslets' do
|
|
177
|
+
|
|
178
|
+
it 'either parslet should apply to generate a match' do
|
|
179
|
+
parslet = RegexpParslet.new(/\d+/) | RegexpParslet.new(/[A-Z]+/)
|
|
180
|
+
parslet.parse('ABC').should == 'ABC'
|
|
181
|
+
parslet.parse('123').should == '123'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'should fail if no parslet generates a match' do
|
|
185
|
+
parslet = RegexpParslet.new(/\d+/) | RegexpParslet.new(/[A-Z]+/)
|
|
186
|
+
lambda { parslet.parse('abc') }.should raise_error(ParseError)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'parslets should be tried in left-to-right order' do
|
|
190
|
+
|
|
191
|
+
# in this case the first parslet should win even though the second one is also a valid match
|
|
192
|
+
parslet = RegexpParslet.new(/(.)(..)/) | RegexpParslet.new(/(..)(.)/)
|
|
193
|
+
match_data = parslet.parse('abc').match_data
|
|
194
|
+
match_data[1].should == 'a'
|
|
195
|
+
match_data[2].should == 'bc'
|
|
196
|
+
|
|
197
|
+
# here we swap the order; again the first parslet should win
|
|
198
|
+
parslet = RegexpParslet.new(/(..)(.)/) | RegexpParslet.new(/(.)(..)/)
|
|
199
|
+
match_data = parslet.parse('abc').match_data
|
|
200
|
+
match_data[1].should == 'ab'
|
|
201
|
+
match_data[2].should == 'c'
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe 'chaining three regexp parslets' do
|
|
208
|
+
|
|
209
|
+
it 'parslets should work in specified order' do
|
|
210
|
+
parslet = RegexpParslet.new(/foo.\d/) & RegexpParslet.new(/bar.\d/) & RegexpParslet.new(/.../)
|
|
211
|
+
parslet.parse('foo_1bar_2ABC').should == ['foo_1', 'bar_2', 'ABC']
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
describe 'alternating three regexp parslets' do
|
|
217
|
+
|
|
218
|
+
it 'any parslet should apply to generate a match' do
|
|
219
|
+
parslet = RegexpParslet.new(/\d+/) | RegexpParslet.new(/[A-Z]+/) | RegexpParslet.new(/[a-z]+/)
|
|
220
|
+
parslet.parse('ABC').should == 'ABC'
|
|
221
|
+
parslet.parse('123').should == '123'
|
|
222
|
+
parslet.parse('abc').should == 'abc'
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it 'should fail if no parslet generates a match' do
|
|
226
|
+
parslet = RegexpParslet.new(/\d+/) | RegexpParslet.new(/[A-Z]+/) | RegexpParslet.new(/[a-z]+/)
|
|
227
|
+
lambda { parslet.parse(':::') }.should raise_error(ParseError)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'parslets should be tried in left-to-right order' do
|
|
231
|
+
|
|
232
|
+
# in this case the first parslet should win even though the others also produce valid matches
|
|
233
|
+
parslet = RegexpParslet.new(/(.)(..)/) | RegexpParslet.new(/(..)(.)/) | RegexpParslet.new(/(...)/)
|
|
234
|
+
match_data = parslet.parse('abc').match_data
|
|
235
|
+
match_data[1].should == 'a'
|
|
236
|
+
match_data[2].should == 'bc'
|
|
237
|
+
|
|
238
|
+
# here we swap the order; again the first parslet should win
|
|
239
|
+
parslet = RegexpParslet.new(/(..)(.)/) | RegexpParslet.new(/(.)(..)/) | RegexpParslet.new(/(...)/)
|
|
240
|
+
match_data = parslet.parse('abc').match_data
|
|
241
|
+
match_data[1].should == 'ab'
|
|
242
|
+
match_data[2].should == 'c'
|
|
243
|
+
|
|
244
|
+
# similar test but this time the first parslet can't win (doesn't match)
|
|
245
|
+
parslet = RegexpParslet.new(/foo/) | RegexpParslet.new(/(...)/) | RegexpParslet.new(/(.)(..)/)
|
|
246
|
+
match_data = parslet.parse('abc').match_data
|
|
247
|
+
match_data[1].should == 'abc'
|
|
248
|
+
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
describe 'combining chaining and alternation' do
|
|
254
|
+
|
|
255
|
+
it 'chaining should having higher precedence than alternation' do
|
|
256
|
+
|
|
257
|
+
# equivalent to /foo/ | ( /bar/ & /abc/ )
|
|
258
|
+
parslet = RegexpParslet.new(/foo/) | RegexpParslet.new(/bar/) & RegexpParslet.new(/abc/)
|
|
259
|
+
parslet.parse('foo').should == 'foo' # succeed on first choice
|
|
260
|
+
parslet.parse('barabc').should == ['bar', 'abc'] # succeed on alternate path
|
|
261
|
+
lambda { parslet.parse('bar...') }.should raise_error(ParseError) # fail half-way down alternate path
|
|
262
|
+
lambda { parslet.parse('lemon') }.should raise_error(ParseError) # fail immediately
|
|
263
|
+
|
|
264
|
+
# swap the order, now equivalent to: ( /bar/ & /abc/ ) | /foo/
|
|
265
|
+
parslet = RegexpParslet.new(/bar/) & RegexpParslet.new(/abc/) | RegexpParslet.new(/foo/)
|
|
266
|
+
parslet.parse('barabc').should == ['bar', 'abc'] # succeed on first choice
|
|
267
|
+
parslet.parse('foo').should == 'foo' # succeed on alternate path
|
|
268
|
+
lambda { parslet.parse('bar...') }.should raise_error(ParseError) # fail half-way down first path
|
|
269
|
+
lambda { parslet.parse('lemon') }.should raise_error(ParseError) # fail immediately
|
|
270
|
+
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it 'should be able to override precedence using parentheses' do
|
|
274
|
+
|
|
275
|
+
# take first example above and make it ( /foo/ | /bar/ ) & /abc/
|
|
276
|
+
parslet = (RegexpParslet.new(/foo/) | RegexpParslet.new(/bar/)) & RegexpParslet.new(/abc/)
|
|
277
|
+
parslet.parse('fooabc').should == ['foo', 'abc'] # first choice
|
|
278
|
+
parslet.parse('barabc').should == ['bar', 'abc'] # second choice
|
|
279
|
+
lambda { parslet.parse('foo...') }.should raise_error(ParseError) # fail in second half
|
|
280
|
+
lambda { parslet.parse('bar...') }.should raise_error(ParseError) # another way of failing in second half
|
|
281
|
+
lambda { parslet.parse('foo') }.should raise_error(ParseError) # another way of failing in second half
|
|
282
|
+
lambda { parslet.parse('bar') }.should raise_error(ParseError) # another way of failing in second half
|
|
283
|
+
lambda { parslet.parse('lemon') }.should raise_error(ParseError) # fail immediately
|
|
284
|
+
lambda { parslet.parse('abcfoo') }.should raise_error(ParseError) # order matters
|
|
285
|
+
|
|
286
|
+
# take second example above and make it /bar/ & ( /abc/ | /foo/ )
|
|
287
|
+
parslet = RegexpParslet.new(/bar/) & (RegexpParslet.new(/abc/) | RegexpParslet.new(/foo/))
|
|
288
|
+
parslet.parse('barabc').should == ['bar', 'abc'] # succeed on first choice
|
|
289
|
+
parslet.parse('barfoo').should == ['bar', 'foo'] # second choice
|
|
290
|
+
lambda { parslet.parse('bar...') }.should raise_error(ParseError) # fail in second part
|
|
291
|
+
lambda { parslet.parse('bar') }.should raise_error(ParseError) # another way to fail in second part
|
|
292
|
+
lambda { parslet.parse('lemon') }.should raise_error(ParseError) # fail immediately
|
|
293
|
+
lambda { parslet.parse('abcbar') }.should raise_error(ParseError) # order matters
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it 'should be able to include long runs of sequences' do
|
|
298
|
+
|
|
299
|
+
# A & B & C & D | E
|
|
300
|
+
parslet = RegexpParslet.new(/a/) & RegexpParslet.new(/b/) & RegexpParslet.new(/c/) & RegexpParslet.new(/d/) | RegexpParslet.new(/e/)
|
|
301
|
+
parslet.parse('abcd').should == ['a', 'b', 'c', 'd']
|
|
302
|
+
parslet.parse('e').should == 'e'
|
|
303
|
+
lambda { parslet.parse('f') }.should raise_error(ParseError)
|
|
304
|
+
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it 'should be able to include long runs of options' do
|
|
308
|
+
|
|
309
|
+
# A | B | C | D & E
|
|
310
|
+
parslet = RegexpParslet.new(/a/) | RegexpParslet.new(/b/) | RegexpParslet.new(/c/) | RegexpParslet.new(/d/) & RegexpParslet.new(/e/)
|
|
311
|
+
parslet.parse('a').should == 'a'
|
|
312
|
+
parslet.parse('b').should == 'b'
|
|
313
|
+
parslet.parse('c').should == 'c'
|
|
314
|
+
parslet.parse('de').should == ['d', 'e']
|
|
315
|
+
lambda { parslet.parse('f') }.should raise_error(ParseError)
|
|
316
|
+
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
it 'should be able to alternate repeatedly between sequences and choices' do
|
|
320
|
+
|
|
321
|
+
# A & B | C & D | E
|
|
322
|
+
parslet = RegexpParslet.new(/a/) & RegexpParslet.new(/b/) | RegexpParslet.new(/c/) & RegexpParslet.new(/d/) | RegexpParslet.new(/e/)
|
|
323
|
+
parslet.parse('ab').should == ['a', 'b']
|
|
324
|
+
parslet.parse('cd').should == ['c', 'd']
|
|
325
|
+
parslet.parse('e').should == 'e'
|
|
326
|
+
lambda { parslet.parse('f') }.should raise_error(ParseError)
|
|
327
|
+
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it 'should be able to combine long runs with alternation' do
|
|
331
|
+
|
|
332
|
+
# A & B & C | D | E | F & G & H
|
|
333
|
+
parslet = RegexpParslet.new(/a/) & RegexpParslet.new(/b/) & RegexpParslet.new(/c/) |
|
|
334
|
+
RegexpParslet.new(/d/) | RegexpParslet.new(/e/) | RegexpParslet.new(/f/) &
|
|
335
|
+
RegexpParslet.new(/g/) & RegexpParslet.new(/h/)
|
|
336
|
+
parslet.parse('abc').should == ['a', 'b', 'c']
|
|
337
|
+
parslet.parse('d').should == 'd'
|
|
338
|
+
parslet.parse('e').should == 'e'
|
|
339
|
+
parslet.parse('fgh').should == ['f', 'g', 'h']
|
|
340
|
+
lambda { parslet.parse('i') }.should raise_error(ParseError)
|
|
341
|
+
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
end # class Grammar
|
|
347
|
+
end # module Walrus
|
|
@@ -0,0 +1,94 @@
|
|
|
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/spec/grammar/string_enumerator_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
10
|
+
|
|
11
|
+
module Walrus
|
|
12
|
+
class Grammar
|
|
13
|
+
|
|
14
|
+
describe 'using a string enumerator' do
|
|
15
|
+
|
|
16
|
+
it 'should raise an ArgumentError if initialized with nil' do
|
|
17
|
+
lambda { StringEnumerator.new(nil) }.should raise_error(ArgumentError)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should return characters one by one until end of string, then return nil' do
|
|
21
|
+
enumerator = StringEnumerator.new('hello')
|
|
22
|
+
enumerator.next.should == 'h'
|
|
23
|
+
enumerator.next.should == 'e'
|
|
24
|
+
enumerator.next.should == 'l'
|
|
25
|
+
enumerator.next.should == 'l'
|
|
26
|
+
enumerator.next.should == 'o'
|
|
27
|
+
enumerator.next.should be_nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'enumerators should be Unicode-aware (UTF-8)' do
|
|
31
|
+
enumerator = StringEnumerator.new('€ cañon')
|
|
32
|
+
enumerator.next.should == '€'
|
|
33
|
+
enumerator.next.should == ' '
|
|
34
|
+
enumerator.next.should == 'c'
|
|
35
|
+
enumerator.next.should == 'a'
|
|
36
|
+
enumerator.next.should == 'ñ'
|
|
37
|
+
enumerator.next.should == 'o'
|
|
38
|
+
enumerator.next.should == 'n'
|
|
39
|
+
enumerator.next.should be_nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# this was a bug
|
|
43
|
+
it 'enumerators should continue past newlines' do
|
|
44
|
+
enumerator = StringEnumerator.new("hello\nworld")
|
|
45
|
+
enumerator.next.should == 'h'
|
|
46
|
+
enumerator.next.should == 'e'
|
|
47
|
+
enumerator.next.should == 'l'
|
|
48
|
+
enumerator.next.should == 'l'
|
|
49
|
+
enumerator.next.should == 'o'
|
|
50
|
+
enumerator.next.should == "\n" # was returning nil here
|
|
51
|
+
enumerator.next.should == 'w'
|
|
52
|
+
enumerator.next.should == 'o'
|
|
53
|
+
enumerator.next.should == 'r'
|
|
54
|
+
enumerator.next.should == 'l'
|
|
55
|
+
enumerator.next.should == 'd'
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'should be able to peek at the next character without actually enumerating' do
|
|
59
|
+
enumerator = StringEnumerator.new('h€llo')
|
|
60
|
+
enumerator.peek.should == 'h' # peek but don't advance
|
|
61
|
+
enumerator.next.should == 'h' # advance
|
|
62
|
+
enumerator.peek.should == '€' # peek a multi-byte character
|
|
63
|
+
enumerator.next.should == '€' # advance a multi-byte character
|
|
64
|
+
enumerator.peek.should == 'l' # peek
|
|
65
|
+
enumerator.peek.should == 'l' # peek the same character again
|
|
66
|
+
enumerator.next.should == 'l' # advance
|
|
67
|
+
enumerator.next.should == 'l' # advance
|
|
68
|
+
enumerator.next.should == 'o' # advance
|
|
69
|
+
enumerator.peek.should == nil # at end should return nil
|
|
70
|
+
enumerator.next.should == nil # nothing left to scan
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'should be able to recall the last character using the "last" method' do
|
|
74
|
+
enumerator = StringEnumerator.new('h€llo')
|
|
75
|
+
enumerator.last.should == nil # nothing scanned yet
|
|
76
|
+
enumerator.next.should == 'h' # advance
|
|
77
|
+
enumerator.last.should == nil # still no previous character
|
|
78
|
+
enumerator.next.should == '€' # advance
|
|
79
|
+
enumerator.last.should == 'h'
|
|
80
|
+
enumerator.next.should == 'l' # advance
|
|
81
|
+
enumerator.last.should == '€'
|
|
82
|
+
enumerator.next.should == 'l' # advance
|
|
83
|
+
enumerator.last.should == 'l'
|
|
84
|
+
enumerator.next.should == 'o' # advance
|
|
85
|
+
enumerator.last.should == 'l'
|
|
86
|
+
enumerator.next.should == nil # nothing left to scan
|
|
87
|
+
enumerator.last.should == 'o'
|
|
88
|
+
enumerator.last.should == 'o' # didn't advance, so should return the same as last time
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end # class Grammar
|
|
94
|
+
end # module Walrus
|
|
@@ -0,0 +1,143 @@
|
|
|
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/spec/grammar/string_parslet_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
10
|
+
|
|
11
|
+
module Walrus
|
|
12
|
+
class Grammar
|
|
13
|
+
|
|
14
|
+
describe 'using a string parslet' do
|
|
15
|
+
|
|
16
|
+
setup do
|
|
17
|
+
@parslet = StringParslet.new('HELLO')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should raise an ArgumentError if initialized with nil' do
|
|
21
|
+
lambda { StringParslet.new(nil) }.should raise_error(ArgumentError)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'parse should succeed if the input string matches' do
|
|
25
|
+
lambda { @parslet.parse('HELLO') }.should_not raise_error
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'parse should succeed if the input string matches, even if it continues after the match' do
|
|
29
|
+
lambda { @parslet.parse('HELLO...') }.should_not raise_error
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'parse should return parsed string' do
|
|
33
|
+
@parslet.parse('HELLO').should == 'HELLO'
|
|
34
|
+
@parslet.parse('HELLO...').should == 'HELLO'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'parse should raise an ArgumentError if passed nil' do
|
|
38
|
+
lambda { @parslet.parse(nil) }.should raise_error(ArgumentError)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'parse should raise a ParseError if the input string does not match' do
|
|
42
|
+
lambda { @parslet.parse('GOODBYE') }.should raise_error(ParseError) # total mismatch
|
|
43
|
+
lambda { @parslet.parse('GOODBYE, HELLO') }.should raise_error(ParseError) # eventually would match, but too late
|
|
44
|
+
lambda { @parslet.parse('HELL...') }.should raise_error(ParseError) # starts well, but fails
|
|
45
|
+
lambda { @parslet.parse(' HELLO') }.should raise_error(ParseError) # note the leading whitespace
|
|
46
|
+
lambda { @parslet.parse('') }.should raise_error(ParseError) # empty strings can't match
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'parse exceptions should include a detailed error message' do
|
|
50
|
+
# TODO: catch the raised exception and compare the message
|
|
51
|
+
lambda { @parslet.parse('HELL...') }.should raise_error(ParseError)
|
|
52
|
+
lambda { @parslet.parse('HELL') }.should raise_error(ParseError)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'should be able to compare string parslets for equality' do
|
|
56
|
+
'foo'.to_parseable.should eql('foo'.to_parseable) # equal
|
|
57
|
+
'foo'.to_parseable.should_not eql('bar'.to_parseable) # different
|
|
58
|
+
'foo'.to_parseable.should_not eql('Foo'.to_parseable) # differing only in case
|
|
59
|
+
'foo'.to_parseable.should_not eql(/foo/) # totally different classes
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'should accurately pack line and column ends into whatever is returned by "parse"' do
|
|
63
|
+
|
|
64
|
+
# single word
|
|
65
|
+
parslet = 'hello'.to_parseable
|
|
66
|
+
result = parslet.parse('hello')
|
|
67
|
+
result.line_end.should == 0
|
|
68
|
+
result.column_end.should == 5
|
|
69
|
+
|
|
70
|
+
# single word with newline at end (UNIX style)
|
|
71
|
+
parslet = "hello\n".to_parseable
|
|
72
|
+
result = parslet.parse("hello\n")
|
|
73
|
+
result.line_end.should == 1
|
|
74
|
+
result.column_end.should == 0
|
|
75
|
+
|
|
76
|
+
# single word with newline at end (Classic Mac style)
|
|
77
|
+
parslet = "hello\r".to_parseable
|
|
78
|
+
result = parslet.parse("hello\r")
|
|
79
|
+
result.line_end.should == 1
|
|
80
|
+
result.column_end.should == 0
|
|
81
|
+
|
|
82
|
+
# single word with newline at end (Windows style)
|
|
83
|
+
parslet = "hello\r\n".to_parseable
|
|
84
|
+
result = parslet.parse("hello\r\n")
|
|
85
|
+
result.line_end.should == 1
|
|
86
|
+
result.column_end.should == 0
|
|
87
|
+
|
|
88
|
+
# two lines (UNIX style)
|
|
89
|
+
parslet = "hello\nworld".to_parseable
|
|
90
|
+
result = parslet.parse("hello\nworld")
|
|
91
|
+
result.line_end.should == 1
|
|
92
|
+
result.column_end.should == 5
|
|
93
|
+
|
|
94
|
+
# two lines (Classic Mac style)
|
|
95
|
+
parslet = "hello\rworld".to_parseable
|
|
96
|
+
result = parslet.parse("hello\rworld")
|
|
97
|
+
result.line_end.should == 1
|
|
98
|
+
result.column_end.should == 5
|
|
99
|
+
|
|
100
|
+
# two lines (Windows style)
|
|
101
|
+
parslet = "hello\r\nworld".to_parseable
|
|
102
|
+
result = parslet.parse("hello\r\nworld")
|
|
103
|
+
result.line_end.should == 1
|
|
104
|
+
result.column_end.should == 5
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'line and column end should reflect last succesfully scanned position prior to failure' do
|
|
109
|
+
|
|
110
|
+
# fail right at start
|
|
111
|
+
parslet = "hello\r\nworld".to_parseable
|
|
112
|
+
begin
|
|
113
|
+
parslet.parse('foobar')
|
|
114
|
+
rescue ParseError => e
|
|
115
|
+
exception = e
|
|
116
|
+
end
|
|
117
|
+
exception.line_end.should == 0
|
|
118
|
+
exception.column_end.should == 0
|
|
119
|
+
|
|
120
|
+
# fail after 1 character
|
|
121
|
+
begin
|
|
122
|
+
parslet.parse('hfoobar')
|
|
123
|
+
rescue ParseError => e
|
|
124
|
+
exception = e
|
|
125
|
+
end
|
|
126
|
+
exception.line_end.should == 0
|
|
127
|
+
exception.column_end.should == 1
|
|
128
|
+
|
|
129
|
+
# fail after end-of-line
|
|
130
|
+
begin
|
|
131
|
+
parslet.parse("hello\r\nfoobar")
|
|
132
|
+
rescue ParseError => e
|
|
133
|
+
exception = e
|
|
134
|
+
end
|
|
135
|
+
exception.line_end.should == 1
|
|
136
|
+
exception.column_end.should == 0
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end # class Grammar
|
|
143
|
+
end # module Walrus
|
|
@@ -0,0 +1,30 @@
|
|
|
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/spec/grammar/symbol_parslet_spec.rb 6702 2007-04-09T15:04:40.448669Z wincent $
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
|
10
|
+
|
|
11
|
+
module Walrus
|
|
12
|
+
class Grammar
|
|
13
|
+
|
|
14
|
+
describe 'using a symbol parslet' do
|
|
15
|
+
|
|
16
|
+
it 'should raise an ArgumentError if initialized with nil' do
|
|
17
|
+
lambda { SymbolParslet.new(nil) }.should raise_error(ArgumentError)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should be able to compare symbol parslets for equality' do
|
|
21
|
+
:foo.to_parseable.should eql(:foo.to_parseable) # equal
|
|
22
|
+
:foo.to_parseable.should_not eql(:bar.to_parseable) # different
|
|
23
|
+
:foo.to_parseable.should_not eql(:Foo.to_parseable) # differing only in case
|
|
24
|
+
:foo.to_parseable.should_not eql(/foo/) # totally different classes
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end # class Grammar
|
|
30
|
+
end # module Walrus
|