Spectre 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +23 -0
- data/README +20 -0
- data/Rakefile +112 -0
- data/lib/spectre/base.rb +44 -0
- data/lib/spectre/base/closure.rb +96 -0
- data/lib/spectre/base/directive.rb +148 -0
- data/lib/spectre/base/grammar.rb +269 -0
- data/lib/spectre/base/inputiterator.rb +276 -0
- data/lib/spectre/base/node.rb +393 -0
- data/lib/spectre/base/operators.rb +342 -0
- data/lib/spectre/base/parser.rb +110 -0
- data/lib/spectre/generic.rb +115 -0
- data/lib/spectre/generic/directives.rb +246 -0
- data/lib/spectre/generic/negations.rb +68 -0
- data/lib/spectre/generic/primitives.rb +172 -0
- data/lib/spectre/generic/semanticaction.rb +43 -0
- data/lib/spectre/string.rb +57 -0
- data/lib/spectre/string/additionals.rb +80 -0
- data/lib/spectre/string/directives.rb +51 -0
- data/lib/spectre/string/inputiterator.rb +57 -0
- data/lib/spectre/string/primitives.rb +400 -0
- data/test/base/closure_tests.rb +108 -0
- data/test/base/grammar_tests.rb +97 -0
- data/test/base/operator_tests.rb +335 -0
- data/test/base/semanticaction_tests.rb +53 -0
- data/test/generic/directive_tests.rb +224 -0
- data/test/generic/negation_tests.rb +146 -0
- data/test/generic/primitive_tests.rb +99 -0
- data/test/string/POD2Parser_tests.rb +93 -0
- data/test/string/additional_tests.rb +43 -0
- data/test/string/directive_tests.rb +32 -0
- data/test/string/primitive_tests.rb +173 -0
- data/test/tests.rb +33 -0
- data/test/tutorial/funnymath_tests.rb +57 -0
- data/test/tutorial/html_tests.rb +171 -0
- data/test/tutorial/skipping_tests.rb +60 -0
- metadata +109 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1 :: First release, basic functionality up, all tests passing
|
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Boost Software License - Version 1.0 - August 17th, 2003
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person or organization
|
4
|
+
obtaining a copy of the software and accompanying documentation covered by
|
5
|
+
this license (the "Software") to use, reproduce, display, distribute,
|
6
|
+
execute, and transmit the Software, and to prepare derivative works of the
|
7
|
+
Software, and to permit third-parties to whom the Software is furnished to
|
8
|
+
do so, all subject to the following:
|
9
|
+
|
10
|
+
The copyright notices in the Software and this entire statement, including
|
11
|
+
the above license grant, this restriction and the following disclaimer,
|
12
|
+
must be included in all copies of the Software, in whole or in part, and
|
13
|
+
all derivative works of the Software, unless such copies or derivative
|
14
|
+
works are solely in the form of machine-executable object code generated by
|
15
|
+
a source language processor.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
20
|
+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
21
|
+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
22
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
23
|
+
DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
This is Spectre, a parser framework inspired by Boost.Spirit,
|
3
|
+
which can be found at http://spirit.sourceforge.net/.
|
4
|
+
|
5
|
+
_______________________________________________________
|
6
|
+
|
7
|
+
License: Boost Software License 1.0
|
8
|
+
For further information regarding this license, visit:
|
9
|
+
http://www.boost.org/LICENSE_1_0.txt
|
10
|
+
______________________________________________________
|
11
|
+
|
12
|
+
|
13
|
+
Support for Spectre is given at http://spectre.rubyforge.org/ .
|
14
|
+
===============================
|
15
|
+
|
16
|
+
If you have questions, problems, want to report bugs or request features, this is the
|
17
|
+
place for you.
|
18
|
+
|
19
|
+
Have fun with it!
|
20
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# This is Spectre, a parser framework inspired by Boost.Spirit,
|
2
|
+
# which can be found at http://spirit.sourceforge.net/.
|
3
|
+
#
|
4
|
+
# If you want to find out more or need a tutorial, go to
|
5
|
+
# http://spectre.rubyforge.org/
|
6
|
+
# You'll find a nice wiki there!
|
7
|
+
#
|
8
|
+
# Author:: Fabian Streitel (karottenreibe)
|
9
|
+
# Copyright:: Copyright (c) 2009 Fabian Streitel
|
10
|
+
# License:: Boost Software License 1.0
|
11
|
+
# For further information regarding this license, you can go to
|
12
|
+
# http://www.boost.org/LICENSE_1_0.txt
|
13
|
+
# or read the file LICENSE distributed with this software.
|
14
|
+
# Homepage:: http://spectre.rubyforge.org/
|
15
|
+
# Git repo:: http://rubyforge.org/scm/?group_id=7618
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'rake/gempackagetask'
|
20
|
+
require 'rake/rdoctask'
|
21
|
+
require 'rake/testtask'
|
22
|
+
|
23
|
+
$VERBOSE = nil
|
24
|
+
|
25
|
+
GEM_NAME = 'Spectre'
|
26
|
+
GEM_AUTHORS = ['Fabian Streitel']
|
27
|
+
GEM_HOMEPAGE = 'http://spectre.rubyforge.org/'
|
28
|
+
GEM_RUBYFORGE = 'spectre'
|
29
|
+
GEM_SUMMARY = "This is Spectre, a parser framework inspired by Boost.Spirit."
|
30
|
+
GEM_EMAIL = "karottenreibe @nospam@ gmail.com"
|
31
|
+
|
32
|
+
spec = Gem::Specification.new do |s|
|
33
|
+
if ARGV.any? { |arg| arg == 'gem' }
|
34
|
+
puts
|
35
|
+
puts
|
36
|
+
puts "Versioning policy:"
|
37
|
+
puts "1 = implementation details changed"
|
38
|
+
puts "2 = compatible new feature"
|
39
|
+
puts "3 = incompatible changes"
|
40
|
+
puts
|
41
|
+
puts "Last build: " + (Dir['pkg/*'].sort)[-1].to_s
|
42
|
+
print "Enter version number > "
|
43
|
+
ver = STDIN.gets.strip
|
44
|
+
print "Enter changelog > "
|
45
|
+
chl = STDIN.gets
|
46
|
+
|
47
|
+
File.open('CHANGELOG', 'a') do |f|
|
48
|
+
f.write "#{ver.ljust 8} :: #{chl}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
s.platform = Gem::Platform::RUBY
|
53
|
+
s.name = GEM_NAME
|
54
|
+
s.version = ver || "99"
|
55
|
+
s.authors = GEM_AUTHORS
|
56
|
+
s.email = GEM_EMAIL
|
57
|
+
s.homepage = GEM_HOMEPAGE
|
58
|
+
s.rubyforge_project = GEM_RUBYFORGE
|
59
|
+
s.summary = GEM_SUMMARY
|
60
|
+
s.files = FileList['lib/**/*.rb', 'test/**/*', '[A-Z]*'].to_a
|
61
|
+
s.require_path = "lib"
|
62
|
+
s.test_files = FileList['test/**/*.rb']
|
63
|
+
s.has_rdoc = true
|
64
|
+
s.extra_rdoc_files = ["README", "CHANGELOG", "LICENSE"]
|
65
|
+
end
|
66
|
+
|
67
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
68
|
+
pkg.need_tar = true
|
69
|
+
end
|
70
|
+
|
71
|
+
task :gem => "pkg/#{GEM_NAME}-#{spec.version}.gem" do
|
72
|
+
puts "generated gem"
|
73
|
+
end
|
74
|
+
|
75
|
+
Rake::RDocTask.new :real_doc do |rdoc|
|
76
|
+
rdoc.rdoc_files.include "lib/**/*.rb"
|
77
|
+
end
|
78
|
+
|
79
|
+
task :doc => [:real_doc] do
|
80
|
+
sh 'rm -r rdoc' if File::exists? 'rdoc'
|
81
|
+
sh 'mv html rdoc'
|
82
|
+
end
|
83
|
+
|
84
|
+
task :clean do
|
85
|
+
sh 'rm -r rdoc'
|
86
|
+
sh 'rm -r pkg'
|
87
|
+
end
|
88
|
+
|
89
|
+
Rake::TestTask.new :test do |t|
|
90
|
+
t.libs << "test"
|
91
|
+
t.test_files = ['test/tests.rb']
|
92
|
+
t.verbose = true
|
93
|
+
end
|
94
|
+
|
95
|
+
task :upload => [:rdoc] do
|
96
|
+
sh "rsync -azv --no-perms --no-times rdoc/* karottenreibe@rubyforge.org:/var/www/gforge-projects/#{GEM_RUBYFORGE}/rdoc/"
|
97
|
+
sh "rsync -azv --no-perms --no-times homepage/* karottenreibe@rubyforge.org:/var/www/gforge-projects/#{GEM_RUBYFORGE}/"
|
98
|
+
end
|
99
|
+
|
100
|
+
task :sftp do
|
101
|
+
sh "sftp karottenreibe@rubyforge.org:/var/www/gforge-projects/#{GEM_RUBYFORGE}/"
|
102
|
+
end
|
103
|
+
|
104
|
+
task :install => [:package] do
|
105
|
+
sh "sudo gem install pkg/#{GEM_NAME}-#{spec.version}.gem"
|
106
|
+
sh "rm pkg/#{GEM_NAME}-#{spec.version}.gem"
|
107
|
+
end
|
108
|
+
|
109
|
+
task :default => [:gem, :doc]
|
110
|
+
task :all => [:clean, :gem, :doc, :test]
|
111
|
+
task :rdoc => [:doc]
|
112
|
+
|
data/lib/spectre/base.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# This is Spectre, a parser framework inspired by Boost.Spirit,
|
2
|
+
# which can be found at http://spirit.sourceforge.net/.
|
3
|
+
#
|
4
|
+
# If you want to find out more or need a tutorial, go to
|
5
|
+
# http://spectre.rubyforge.org/
|
6
|
+
# You'll find a nice wiki there!
|
7
|
+
#
|
8
|
+
# Author:: Fabian Streitel (karottenreibe)
|
9
|
+
# Copyright:: Copyright (c) 2009 Fabian Streitel
|
10
|
+
# License:: Boost Software License 1.0
|
11
|
+
# For further information regarding this license, you can go to
|
12
|
+
# http://www.boost.org/LICENSE_1_0.txt
|
13
|
+
# or read the file LICENSE distributed with this software.
|
14
|
+
# Homepage:: http://spectre.rubyforge.org/
|
15
|
+
# Git repo:: http://rubyforge.org/scm/?group_id=7618
|
16
|
+
#
|
17
|
+
# Requires the base classes needed for Spectre to work:
|
18
|
+
# InputIterator, Node, Parser, Grammar and Closure as well as the default
|
19
|
+
# Operators, semantic actions and Directives.
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'spectre/base/inputiterator'
|
23
|
+
require 'spectre/base/node'
|
24
|
+
require 'spectre/base/parser'
|
25
|
+
require 'spectre/base/grammar'
|
26
|
+
require 'spectre/base/closure'
|
27
|
+
require 'spectre/base/operators'
|
28
|
+
require 'spectre/base/directive'
|
29
|
+
|
30
|
+
module Spectre
|
31
|
+
|
32
|
+
class << self
|
33
|
+
##
|
34
|
+
# Shortcut. Parses the +input+ using +parser+ (Parser or Node) and the InputIterator
|
35
|
+
# class +iter_klass+.
|
36
|
+
# +pre_skip+ will be passed on to +Node#parse+.
|
37
|
+
#
|
38
|
+
def parse input, parser, iter_klass, pre_skip = true
|
39
|
+
parser.to_p.parse iter_klass.new(input), pre_skip
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# This is Spectre, a parser framework inspired by Boost.Spirit,
|
2
|
+
# which can be found at http://spirit.sourceforge.net/.
|
3
|
+
#
|
4
|
+
# If you want to find out more or need a tutorial, go to
|
5
|
+
# http://spectre.rubyforge.org/
|
6
|
+
# You'll find a nice wiki there!
|
7
|
+
#
|
8
|
+
# Author:: Fabian Streitel (karottenreibe)
|
9
|
+
# Copyright:: Copyright (c) 2009 Fabian Streitel
|
10
|
+
# License:: Boost Software License 1.0
|
11
|
+
# For further information regarding this license, you can go to
|
12
|
+
# http://www.boost.org/LICENSE_1_0.txt
|
13
|
+
# or read the file LICENSE distributed with this software.
|
14
|
+
# Homepage:: http://spectre.rubyforge.org/
|
15
|
+
# Git repo:: http://rubyforge.org/scm/?group_id=7618
|
16
|
+
#
|
17
|
+
# Keeps the Closure class.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'spectre/base/parser'
|
21
|
+
require 'spectre/base/grammar'
|
22
|
+
|
23
|
+
module Spectre
|
24
|
+
|
25
|
+
##
|
26
|
+
# Provides a Closure over several semantic actions to allow them to interact with each other
|
27
|
+
# and temporarily store data.
|
28
|
+
# The default Closure is a simple hash, but actually it can be an arbitrary object, as long as
|
29
|
+
# it provides the Hash methods +[]+ and +[]=+ and the attributes +parser+ and +node+.
|
30
|
+
#
|
31
|
+
class Closure < Hash
|
32
|
+
|
33
|
+
##
|
34
|
+
# The Parser this Closure belongs to.
|
35
|
+
attr_accessor :parser
|
36
|
+
|
37
|
+
##
|
38
|
+
# The Node this Closure belongs to.
|
39
|
+
attr_accessor :node
|
40
|
+
|
41
|
+
def parent
|
42
|
+
@parser.parent.closure
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Retrieves a value from the Closure and uses it as a Parser.
|
48
|
+
# The retrieval is performed at parse time.
|
49
|
+
#
|
50
|
+
class ClosureParser
|
51
|
+
include Parser
|
52
|
+
|
53
|
+
##
|
54
|
+
# The symbol that identifies the Parser inside the Closure.
|
55
|
+
attr_reader :sym
|
56
|
+
|
57
|
+
##
|
58
|
+
# +sym+ is the identifier for the value retrieved from the Closure.
|
59
|
+
#
|
60
|
+
def initialize sym
|
61
|
+
@sym = sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def negation; NegatedClosureParser.new @sym; end
|
65
|
+
|
66
|
+
def scan iter
|
67
|
+
raise "symbol #{@sym.inspect} not found in closure #{@node.closure.inspect}" unless
|
68
|
+
@node.closure and @node.closure[@sym]
|
69
|
+
create_match iter, @node.closure[@sym].to_p.parse(iter)
|
70
|
+
end
|
71
|
+
|
72
|
+
def inspect
|
73
|
+
"[closure:#{@sym}]"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Negates the enclosed parser.
|
79
|
+
#
|
80
|
+
class NegatedClosureParser < ClosureParser
|
81
|
+
def scan iter
|
82
|
+
raise "symbol #{@sym.inspect} not found in closure #{@node.closure.inspect}" unless
|
83
|
+
@node.closure and @node.closure[@sym]
|
84
|
+
create_match iter, ( ~( @node.closure[@sym].to_p ) ).parse(iter)
|
85
|
+
end
|
86
|
+
|
87
|
+
def inspect
|
88
|
+
"(~[closure:#{@sym}])"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# The ClosureParser shortcut is +closed+.
|
94
|
+
ShortcutsMixin.register_shortcut :closed => ClosureParser
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# This is Spectre, a parser framework inspired by Boost.Spirit,
|
2
|
+
# which can be found at http://spirit.sourceforge.net/.
|
3
|
+
#
|
4
|
+
# If you want to find out more or need a tutorial, go to
|
5
|
+
# http://spectre.rubyforge.org/
|
6
|
+
# You'll find a nice wiki there!
|
7
|
+
#
|
8
|
+
# Author:: Fabian Streitel (karottenreibe)
|
9
|
+
# Copyright:: Copyright (c) 2009 Fabian Streitel
|
10
|
+
# License:: Boost Software License 1.0
|
11
|
+
# For further information regarding this license, you can go to
|
12
|
+
# http://www.boost.org/LICENSE_1_0.txt
|
13
|
+
# or read the file LICENSE distributed with this software.
|
14
|
+
# Homepage:: http://spectre.rubyforge.org/
|
15
|
+
# Git repo:: http://rubyforge.org/scm/?group_id=7618
|
16
|
+
#
|
17
|
+
# Keeps the Directive class.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'spectre/base/parser'
|
21
|
+
require 'spectre/base/node'
|
22
|
+
|
23
|
+
module Spectre
|
24
|
+
|
25
|
+
##
|
26
|
+
# Sets options for the Parser and InputIterator.
|
27
|
+
# Imitates the behaviour of a Node.
|
28
|
+
# Subclasses may call the singleton methods +::transformation!+ and +::policy!+ to set the input
|
29
|
+
# transformation and Parser policy hash to use.
|
30
|
+
# These hashes will get merged with the current options.
|
31
|
+
#
|
32
|
+
# The Directive acts like a node in order to apply the parser policy.
|
33
|
+
# It keeps a DirectiveParser, which applies the input transformation.
|
34
|
+
#
|
35
|
+
class Directive < Node
|
36
|
+
|
37
|
+
##
|
38
|
+
# The skipper to apply to the InputIterator for this Directive - lambda block.
|
39
|
+
attr_reader :iter_skipper
|
40
|
+
|
41
|
+
##
|
42
|
+
# The transformation to apply to the InputIterator for this Directive - lambda block.
|
43
|
+
attr_reader :iter_transformation
|
44
|
+
|
45
|
+
##
|
46
|
+
# Whether or not the child parser should do pre-skipping.
|
47
|
+
attr_reader :pre_skip
|
48
|
+
|
49
|
+
class << self
|
50
|
+
|
51
|
+
##
|
52
|
+
# The skipper to apply to the InputIterator for this subclass - lambda block.
|
53
|
+
attr_reader :skipper
|
54
|
+
|
55
|
+
##
|
56
|
+
# The transformation to apply to the InputIterator for this subclass - lambda block.
|
57
|
+
attr_reader :transformation
|
58
|
+
|
59
|
+
##
|
60
|
+
# The options to merge with the Parser options for this subclass.
|
61
|
+
#
|
62
|
+
def policy
|
63
|
+
@policy || {}
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Sets the skipper on the InputIterator for this subclass to either the +block+
|
68
|
+
# or if no block is given to the first argument given to the method.
|
69
|
+
#
|
70
|
+
def skipper! *args, &block
|
71
|
+
@skipper = block_given? ? block : args[0]
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Sets the input transformation on the InputIterator for this subclass to either the +block+
|
76
|
+
# or if no block is given to the first argument given to the method.
|
77
|
+
#
|
78
|
+
def transformation! *args, &block
|
79
|
+
@transformation = block_given? ? block : args[0]
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Sets the Parser policy to use for this subclass.
|
84
|
+
# The provided +hash+ will be merged with any already existing policy hash, thus enabling
|
85
|
+
# you to leave current specifications the way they are by simply not mentioning them.
|
86
|
+
#
|
87
|
+
def policy! hash
|
88
|
+
@policy = hash
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Retrieves the options from the subclassclass definition.
|
94
|
+
#
|
95
|
+
def initialize
|
96
|
+
@iter_transformation ||= self.class.transformation
|
97
|
+
@iter_skipper ||= self.class.skipper
|
98
|
+
@pre_skip = true
|
99
|
+
super(DirectiveParser.new self)
|
100
|
+
pol = self.class.policy
|
101
|
+
@policy ? @policy.merge!(pol) : @policy = pol
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Unlike Nodes, the Directive cannot store semantic actions. Instead this operator is used to
|
106
|
+
# deliver the subnodes for it.
|
107
|
+
# Performs auto-conversion on +node+.
|
108
|
+
#
|
109
|
+
def [] node
|
110
|
+
@left = node.to_p
|
111
|
+
@left.parent = self
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Saves the pre_skipping flag as directives pass that on to their children.
|
117
|
+
#
|
118
|
+
def parse iter, pre_skip = true
|
119
|
+
@pre_skip = pre_skip
|
120
|
+
super(iter, pre_skip)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Does the setting and resetting of the input transformation on the InputIterator.
|
126
|
+
#
|
127
|
+
class DirectiveParser
|
128
|
+
include Parser
|
129
|
+
|
130
|
+
def initialize directive
|
131
|
+
@directive = directive
|
132
|
+
end
|
133
|
+
|
134
|
+
def scan iter
|
135
|
+
trans, skip = iter.transformation, iter.skipper
|
136
|
+
iter.transformation = @directive.iter_transformation if @directive.iter_transformation
|
137
|
+
iter.skipper = @directive.iter_skipper if @directive.iter_skipper
|
138
|
+
|
139
|
+
ret = @node.left.parse iter, @directive.pre_skip
|
140
|
+
|
141
|
+
iter.transformation, iter.skipper = trans, skip
|
142
|
+
|
143
|
+
create_match iter, ret
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|