pegarus 0.1.0
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/LICENSE +22 -0
- data/README +24 -0
- data/Rakefile +70 -0
- data/lib/pegarus/ast/always.rb +7 -0
- data/lib/pegarus/ast/any.rb +13 -0
- data/lib/pegarus/ast/any_range.rb +13 -0
- data/lib/pegarus/ast/character.rb +13 -0
- data/lib/pegarus/ast/character_range.rb +13 -0
- data/lib/pegarus/ast/choice.rb +7 -0
- data/lib/pegarus/ast/concatenation.rb +7 -0
- data/lib/pegarus/ast/difference.rb +7 -0
- data/lib/pegarus/ast/grammar.rb +56 -0
- data/lib/pegarus/ast/if.rb +9 -0
- data/lib/pegarus/ast/never.rb +7 -0
- data/lib/pegarus/ast/pattern.rb +127 -0
- data/lib/pegarus/ast/product.rb +12 -0
- data/lib/pegarus/ast/set.rb +13 -0
- data/lib/pegarus/ast/unless.rb +9 -0
- data/lib/pegarus/ast/variable.rb +15 -0
- data/lib/pegarus/ast.rb +16 -0
- data/lib/pegarus/compatibility.rb +25 -0
- data/lib/pegarus/evaluator.rb +93 -0
- data/lib/pegarus/machine/compiler.rb +18 -0
- data/lib/pegarus/machine/generator.rb +8 -0
- data/lib/pegarus/machine/instructions.rb +65 -0
- data/lib/pegarus/machine/interpreter.rb +31 -0
- data/lib/pegarus/machine/state.rb +29 -0
- data/lib/pegarus/machine.rb +15 -0
- data/lib/pegarus/parser/parse_error.rb +3 -0
- data/lib/pegarus/parser.rb +1 -0
- data/lib/pegarus/rubinius/compiler.rb +220 -0
- data/lib/pegarus/rubinius/generator.rb +48 -0
- data/lib/pegarus/rubinius.rb +4 -0
- data/lib/pegarus/version.rb +3 -0
- data/lib/pegarus.rb +3 -0
- data/spec/ast/choice_spec.rb +9 -0
- data/spec/ast/concatenation_spec.rb +9 -0
- data/spec/ast/difference_spec.rb +9 -0
- data/spec/ast/grammar_spec.rb +54 -0
- data/spec/ast/if_spec.rb +8 -0
- data/spec/ast/pattern_spec.rb +123 -0
- data/spec/ast/product_spec.rb +28 -0
- data/spec/ast/unless_spec.rb +8 -0
- data/spec/ast/variable_spec.rb +4 -0
- data/spec/custom/guards/engine.rb +27 -0
- data/spec/machine/instructions/call_spec.rb +21 -0
- data/spec/machine/instructions/capture_spec.rb +15 -0
- data/spec/machine/instructions/char_spec.rb +34 -0
- data/spec/machine/instructions/choice_spec.rb +15 -0
- data/spec/machine/instructions/commit_spec.rb +21 -0
- data/spec/machine/instructions/fail_spec.rb +34 -0
- data/spec/machine/instructions/jump_spec.rb +15 -0
- data/spec/machine/instructions/return_spec.rb +16 -0
- data/spec/matching/evaluator/any_spec.rb +6 -0
- data/spec/matching/evaluator/character_spec.rb +6 -0
- data/spec/matching/evaluator/choice_spec.rb +6 -0
- data/spec/matching/evaluator/concatenation_spec.rb +6 -0
- data/spec/matching/evaluator/difference_spec.rb +6 -0
- data/spec/matching/evaluator/if_spec.rb +6 -0
- data/spec/matching/evaluator/product_spec.rb +6 -0
- data/spec/matching/evaluator/setup.rb +4 -0
- data/spec/matching/evaluator/unless_spec.rb +6 -0
- data/spec/matching/machine/any_spec.rb +6 -0
- data/spec/matching/machine/character_spec.rb +6 -0
- data/spec/matching/machine/choice_spec.rb +6 -0
- data/spec/matching/machine/concatenation_spec.rb +6 -0
- data/spec/matching/machine/difference_spec.rb +6 -0
- data/spec/matching/machine/if_spec.rb +6 -0
- data/spec/matching/machine/product_spec.rb +6 -0
- data/spec/matching/machine/setup.rb +4 -0
- data/spec/matching/machine/unless_spec.rb +6 -0
- data/spec/matching/rubinius/any_spec.rb +8 -0
- data/spec/matching/rubinius/character_spec.rb +8 -0
- data/spec/matching/rubinius/choice_spec.rb +8 -0
- data/spec/matching/rubinius/concatenation_spec.rb +8 -0
- data/spec/matching/rubinius/difference_spec.rb +8 -0
- data/spec/matching/rubinius/if_spec.rb +8 -0
- data/spec/matching/rubinius/product_spec.rb +8 -0
- data/spec/matching/rubinius/setup.rb +4 -0
- data/spec/matching/rubinius/unless_spec.rb +8 -0
- data/spec/matching/shared/any.rb +13 -0
- data/spec/matching/shared/character.rb +17 -0
- data/spec/matching/shared/choice.rb +16 -0
- data/spec/matching/shared/concatenation.rb +16 -0
- data/spec/matching/shared/difference.rb +2 -0
- data/spec/matching/shared/if.rb +16 -0
- data/spec/matching/shared/product.rb +2 -0
- data/spec/matching/shared/unless.rb +16 -0
- data/spec/spec_helper.rb +12 -0
- metadata +166 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2010 Brian Ford. All rights reserved.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Pegarus is, broadly, an implementation of LPEG on Rubinius. LPEG implements a
|
2
|
+
Parsing Expression Grammar using a parsing machine rather than the Packrat
|
3
|
+
algorithm. (See "A Text Pattern-Matching Tool based on Parsing Expression
|
4
|
+
Grammars" by Roberto Ierusalimschy.)
|
5
|
+
|
6
|
+
Pegarus actually implements an abstract syntax tree (AST) for the PEG. There
|
7
|
+
are various options to execute the AST against a subject string. One option is
|
8
|
+
a simple AST-walking evaluator. A second option is an implementation of the
|
9
|
+
LPEG parsing machine. A third option is a compiler that targets Rubinius
|
10
|
+
bytecode.
|
11
|
+
|
12
|
+
|
13
|
+
1. Running the specs
|
14
|
+
|
15
|
+
Pegarus uses the mspec gem because of the facilities for tags and easily
|
16
|
+
defining custom matchers and guards, since Pegarus targets more than one Ruby
|
17
|
+
implementation.
|
18
|
+
|
19
|
+
To run the specs, use the following steps:
|
20
|
+
|
21
|
+
1. Install the mspec gem
|
22
|
+
2. If you plan to use Rubinius, ensure 'rbx' is on your path
|
23
|
+
3. Run 'rake' to run the specs with $RUBY or 'rbx'
|
24
|
+
4. Set the environment variable RUBY to the name of the Ruby to use
|
data/Rakefile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
|
3
|
+
task :default => :spec
|
4
|
+
|
5
|
+
BASE_DIR = File.expand_path('../', __FILE__)
|
6
|
+
RUBY = ENV["RUBY"] || "rbx"
|
7
|
+
|
8
|
+
def spec(target)
|
9
|
+
sh("mspec -t #{target} -T -I#{BASE_DIR} spec") { |ok, res| }
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Run the specs with $RUBY or 'rbx' (default)"
|
13
|
+
task :spec do
|
14
|
+
spec RUBY
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :spec do
|
18
|
+
desc "Run the specs with Rubinius"
|
19
|
+
task :rbx do
|
20
|
+
spec "rbx"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Run the specs with the 'ruby' on $PATH"
|
24
|
+
task :ruby do
|
25
|
+
spec "ruby"
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Run the specs with all engines"
|
29
|
+
task :all => [:rbx, :ruby]
|
30
|
+
end
|
31
|
+
|
32
|
+
spec = Gem::Specification.new do |s|
|
33
|
+
require File.expand_path('../lib/pegarus/version', __FILE__)
|
34
|
+
|
35
|
+
s.name = "pegarus"
|
36
|
+
s.version = Pegarus::VERSION.to_s
|
37
|
+
|
38
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
39
|
+
|
40
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
41
|
+
s.authors = ["Brian Ford"]
|
42
|
+
s.date = %q{2010-10-24}
|
43
|
+
s.email = %q{brixen@gmail.com}
|
44
|
+
s.has_rdoc = true
|
45
|
+
s.extra_rdoc_files = %w[ README LICENSE ]
|
46
|
+
s.executables = []
|
47
|
+
s.files = FileList[ '{bin,lib,spec}/**/*.{yaml,txt,rb}', 'Rakefile', *s.extra_rdoc_files ]
|
48
|
+
s.homepage = %q{http://github.com/brixen/pegarus}
|
49
|
+
s.require_paths = ["lib"]
|
50
|
+
s.rubygems_version = %q{1.3.5}
|
51
|
+
s.summary = "Pegarus is an implementation of LPEG in Ruby."
|
52
|
+
s.description = <<EOS
|
53
|
+
Pegarus is, broadly, an implementation of LPEG on Rubinius. LPEG implements a
|
54
|
+
Parsing Expression Grammar using a parsing machine rather than the Packrat
|
55
|
+
algorithm. (See "A Text Pattern-Matching Tool based on Parsing Expression
|
56
|
+
Grammars" by Roberto Ierusalimschy.)
|
57
|
+
|
58
|
+
Pegarus actually implements an abstract syntax tree (AST) for the PEG. There
|
59
|
+
are various options to execute the AST against a subject string. One option is
|
60
|
+
a simple AST-walking evaluator. A second option is an implementation of the
|
61
|
+
LPEG parsing machine. A third option is a compiler that targets Rubinius
|
62
|
+
bytecode.
|
63
|
+
EOS
|
64
|
+
|
65
|
+
s.rdoc_options << '--title' << 'Pegarus Gem' <<
|
66
|
+
'--main' << 'README' <<
|
67
|
+
'--line-numbers'
|
68
|
+
end
|
69
|
+
|
70
|
+
Rake::GemPackageTask.new(spec){ |pkg| pkg.gem_spec = spec }
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Pegarus
|
2
|
+
def grammar(spec=nil, pattern=nil)
|
3
|
+
case spec
|
4
|
+
when Symbol
|
5
|
+
Grammar.new Variable.new(spec, pattern)
|
6
|
+
when Variable
|
7
|
+
Grammar.new spec
|
8
|
+
when Pattern
|
9
|
+
Grammar.new Variable.new(:S, spec)
|
10
|
+
when nil
|
11
|
+
Grammar.new
|
12
|
+
else
|
13
|
+
Grammar.new Variable.new(:S, pattern)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
module_function :grammar
|
17
|
+
|
18
|
+
class Grammar < Pattern
|
19
|
+
attr_accessor :start
|
20
|
+
|
21
|
+
def initialize(variable=nil)
|
22
|
+
if variable
|
23
|
+
@start = variable.name
|
24
|
+
set_variable variable.name, variable.pattern
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_variable(name, *pattern)
|
29
|
+
variable = get_variable name
|
30
|
+
variable.pattern = *pattern
|
31
|
+
variable
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_variable(name)
|
35
|
+
if metaclass.method_defined? name
|
36
|
+
variable = send name
|
37
|
+
else
|
38
|
+
vname = name.to_sym
|
39
|
+
variable = Variable.new vname
|
40
|
+
metaclass.thunk_method vname, variable
|
41
|
+
end
|
42
|
+
|
43
|
+
variable
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(sym, *args)
|
47
|
+
name = sym.to_s
|
48
|
+
|
49
|
+
if name[-1] == ?=
|
50
|
+
set_variable name[0..-2], *args
|
51
|
+
else
|
52
|
+
get_variable name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Pegarus
|
2
|
+
# Accepts a Ruby object representation of simple PEG "atoms" and returns an
|
3
|
+
# AST node.
|
4
|
+
def pattern(spec)
|
5
|
+
case spec
|
6
|
+
when Array
|
7
|
+
Set.new spec.join
|
8
|
+
when Integer
|
9
|
+
Any.new spec
|
10
|
+
when String
|
11
|
+
Character.new spec
|
12
|
+
when Range
|
13
|
+
case spec.first
|
14
|
+
when Integer
|
15
|
+
AnyRange.new spec
|
16
|
+
when String
|
17
|
+
CharacterRange.new spec
|
18
|
+
end
|
19
|
+
when Symbol
|
20
|
+
variable spec
|
21
|
+
when Pattern
|
22
|
+
spec
|
23
|
+
when true
|
24
|
+
Always.new
|
25
|
+
when false
|
26
|
+
Never.new
|
27
|
+
when nil
|
28
|
+
nil
|
29
|
+
else
|
30
|
+
raise ParseError, "unknown specification type for Pattern: #{spec.inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
module_function :pattern
|
34
|
+
|
35
|
+
|
36
|
+
# Class Pattern is the base class for all nodes used to represent the AST
|
37
|
+
# for a PEG. Following LPEG, the base is a pattern and not a grammar.
|
38
|
+
class Pattern
|
39
|
+
# Executes the PEG pattern on subject. If the pattern matches a prefix of
|
40
|
+
# subject, returns the index one character past the last matching
|
41
|
+
# character. Otherwise, returns nil.
|
42
|
+
#
|
43
|
+
# The pattern AST is purely a representation. By default, it includes no
|
44
|
+
# machinery to execute the pattern over the subject. All execution is
|
45
|
+
# provided by other facilities, for example, the AST evaluator and the
|
46
|
+
# parsing machine compiler and interpreter. These facilities are called
|
47
|
+
# "engines".
|
48
|
+
#
|
49
|
+
# The Pattern class defaults to the AST Evaluator engine. The protocol
|
50
|
+
# requires the engine class to respond to .new_exector taking the AST root
|
51
|
+
# node and the subject as arguments. The default Pattern#match method is
|
52
|
+
# essentially a trampoline. It calls new_executor and expects that method
|
53
|
+
# to replace #match on the root node and then tail call to the new #match
|
54
|
+
# method installed by the engine.
|
55
|
+
|
56
|
+
def match(subject)
|
57
|
+
Pattern.engine.new_executor self, subject
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.engine
|
61
|
+
unless @engine
|
62
|
+
require 'pegarus/evaluator'
|
63
|
+
@engine = Evaluator
|
64
|
+
end
|
65
|
+
|
66
|
+
@engine
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.select_engine(klass)
|
70
|
+
@engine = klass
|
71
|
+
end
|
72
|
+
|
73
|
+
def graph
|
74
|
+
if defined? Rubinius
|
75
|
+
Rubinius::AST::AsciiGrapher.new(self, Pattern).print
|
76
|
+
else
|
77
|
+
inspect
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def visit(visitor)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Pattern operators
|
85
|
+
|
86
|
+
def /(other)
|
87
|
+
Choice.new self, other
|
88
|
+
end
|
89
|
+
|
90
|
+
def +(other)
|
91
|
+
Concatenation.new self, other
|
92
|
+
end
|
93
|
+
|
94
|
+
def -(other)
|
95
|
+
Difference.new self, other
|
96
|
+
end
|
97
|
+
|
98
|
+
def *(other)
|
99
|
+
Product.new self, other
|
100
|
+
end
|
101
|
+
|
102
|
+
def +@
|
103
|
+
If.new self
|
104
|
+
end
|
105
|
+
|
106
|
+
def -@
|
107
|
+
Unless.new self
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class UnaryOp < Pattern
|
112
|
+
attr_accessor :pattern
|
113
|
+
|
114
|
+
def initialize(pattern)
|
115
|
+
@pattern = Pegarus.pattern pattern
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class BinaryOp < Pattern
|
120
|
+
attr_accessor :first, :second
|
121
|
+
|
122
|
+
def initialize(first, second)
|
123
|
+
@first = Pegarus.pattern first
|
124
|
+
@second = Pegarus.pattern second
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pegarus
|
2
|
+
def variable(name, pattern=nil)
|
3
|
+
Pegarus::Variable.new name, pattern
|
4
|
+
end
|
5
|
+
module_function :variable
|
6
|
+
|
7
|
+
class Variable < Pattern
|
8
|
+
attr_accessor :name, :pattern
|
9
|
+
|
10
|
+
def initialize(name, pattern=nil)
|
11
|
+
@name = name.to_sym
|
12
|
+
@pattern = Pegarus.pattern pattern
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/pegarus/ast.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pegarus/ast/pattern'
|
2
|
+
require 'pegarus/ast/always'
|
3
|
+
require 'pegarus/ast/any'
|
4
|
+
require 'pegarus/ast/any_range'
|
5
|
+
require 'pegarus/ast/character'
|
6
|
+
require 'pegarus/ast/character_range'
|
7
|
+
require 'pegarus/ast/choice'
|
8
|
+
require 'pegarus/ast/concatenation'
|
9
|
+
require 'pegarus/ast/difference'
|
10
|
+
require 'pegarus/ast/if'
|
11
|
+
require 'pegarus/ast/never'
|
12
|
+
require 'pegarus/ast/product'
|
13
|
+
require 'pegarus/ast/set'
|
14
|
+
require 'pegarus/ast/unless'
|
15
|
+
require 'pegarus/ast/grammar'
|
16
|
+
require 'pegarus/ast/variable'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Module
|
2
|
+
unless method_defined? :thunk_method
|
3
|
+
def thunk_method(name, value)
|
4
|
+
define_method(name) { return value }
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
unless defined?(Type)
|
10
|
+
module Type
|
11
|
+
def self.coerce_to(obj, cls, meth)
|
12
|
+
return obj if obj.kind_of? cls
|
13
|
+
|
14
|
+
begin
|
15
|
+
ret = obj.__send__(meth)
|
16
|
+
rescue Exception
|
17
|
+
raise TypeError, "Coercion error: #{obj.inspect}.#{meth} => #{cls} failed"
|
18
|
+
end
|
19
|
+
|
20
|
+
return ret if ret.kind_of? cls
|
21
|
+
|
22
|
+
raise TypeError, "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{ret.class})"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Pegarus
|
2
|
+
class Evaluator
|
3
|
+
def self.new_executor(pattern, subject)
|
4
|
+
pattern.instance_variable_set :@evaluator, new
|
5
|
+
|
6
|
+
class << pattern
|
7
|
+
class_eval <<-eval
|
8
|
+
def match(subject)
|
9
|
+
@evaluator.match self, subject
|
10
|
+
end
|
11
|
+
eval
|
12
|
+
end
|
13
|
+
|
14
|
+
pattern.match subject
|
15
|
+
end
|
16
|
+
|
17
|
+
def match(pattern, subject)
|
18
|
+
@subject = subject
|
19
|
+
@failure = false
|
20
|
+
@index = 0
|
21
|
+
|
22
|
+
pattern.visit self
|
23
|
+
|
24
|
+
failure? ? nil : @index
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure
|
28
|
+
@failure = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure?
|
32
|
+
@failure
|
33
|
+
end
|
34
|
+
|
35
|
+
def always(pattern)
|
36
|
+
failure
|
37
|
+
end
|
38
|
+
|
39
|
+
def any(pattern)
|
40
|
+
if @subject.size > @index + pattern.count
|
41
|
+
@index += pattern.count
|
42
|
+
else
|
43
|
+
failure
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def any_range(pattern)
|
48
|
+
failure
|
49
|
+
end
|
50
|
+
|
51
|
+
def character(pattern)
|
52
|
+
failure
|
53
|
+
end
|
54
|
+
|
55
|
+
def character_range(pattern)
|
56
|
+
failure
|
57
|
+
end
|
58
|
+
|
59
|
+
def choice(pattern)
|
60
|
+
failure
|
61
|
+
end
|
62
|
+
|
63
|
+
def concatenation(pattern)
|
64
|
+
failure
|
65
|
+
end
|
66
|
+
|
67
|
+
def difference(pattern)
|
68
|
+
failure
|
69
|
+
end
|
70
|
+
|
71
|
+
def if(pattern)
|
72
|
+
failure
|
73
|
+
end
|
74
|
+
|
75
|
+
def never(pattern)
|
76
|
+
failure
|
77
|
+
end
|
78
|
+
|
79
|
+
def product(pattern)
|
80
|
+
failure
|
81
|
+
end
|
82
|
+
|
83
|
+
def set(pattern)
|
84
|
+
failure
|
85
|
+
end
|
86
|
+
|
87
|
+
def unless(pattern)
|
88
|
+
failure
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
Pegarus::Pattern.select_engine Pegarus::Evaluator
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pegarus
|
2
|
+
module Machine
|
3
|
+
class Compiler
|
4
|
+
def compile(pattern)
|
5
|
+
program = []
|
6
|
+
pattern.instance_variable_set :@program, program
|
7
|
+
|
8
|
+
class << pattern
|
9
|
+
class_eval <<-eval
|
10
|
+
def match(subject)
|
11
|
+
Pegarus::Machine.execute @program, subject
|
12
|
+
end
|
13
|
+
eval
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|