pegarus 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,27 @@
|
|
1
|
+
class EngineGuard < SpecGuard
|
2
|
+
def match?
|
3
|
+
if defined?(RUBY_ENGINE)
|
4
|
+
@args.any? { |name| RUBY_ENGINE == name.to_s }
|
5
|
+
else
|
6
|
+
false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Object
|
12
|
+
def engine_is(*names)
|
13
|
+
g = EngineGuard.new(*names)
|
14
|
+
g.name = :engine_is
|
15
|
+
yield if g.yield?
|
16
|
+
ensure
|
17
|
+
g.unregister
|
18
|
+
end
|
19
|
+
|
20
|
+
def engine_is_not(*names)
|
21
|
+
g = EngineGuard.new(*names)
|
22
|
+
g.name = :engine_is_not
|
23
|
+
yield if g.yield? true
|
24
|
+
ensure
|
25
|
+
g.unregister
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The call instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:call]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "pushes the next IP onto the stack" do
|
11
|
+
@state.stack.should == []
|
12
|
+
@insn[@state, 5]
|
13
|
+
@state.stack.should == [2]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the IP to the value of the argument" do
|
17
|
+
@state.ip.should == 0
|
18
|
+
@insn[@state, 5]
|
19
|
+
@state.ip.should == 5
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The capture instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:capture]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "adds an entry [current index, <data>] in the captures list" do
|
11
|
+
@state.captures.should == []
|
12
|
+
@insn[@state, :data]
|
13
|
+
@state.captures.should == [[0, :data]]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The char instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new "abc"
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:char]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "advances the subject index if the character matches" do
|
11
|
+
@state.index.should == 0
|
12
|
+
@insn[@state, ?a]
|
13
|
+
@state.index.should == 1
|
14
|
+
end
|
15
|
+
|
16
|
+
it "does not advance the subject index if the charater does not match" do
|
17
|
+
@state.index.should == 0
|
18
|
+
@insn[@state, ?b]
|
19
|
+
@state.index.should == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets the machine state to failure if current index exceeds subject length" do
|
23
|
+
state = Pegarus::Machine::State.new ""
|
24
|
+
state.failure?.should be_false
|
25
|
+
@insn[state, ?a]
|
26
|
+
state.failure?.should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "sets the machine state to failure if the character does not match" do
|
30
|
+
@state.failure?.should be_false
|
31
|
+
@insn[@state, ?b]
|
32
|
+
@state.failure?.should be_true
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The choice instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:choice]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "pushes the alternate IP, current subject index, and captures list on the stack" do
|
11
|
+
@state.stack.should == []
|
12
|
+
@insn[@state, 5]
|
13
|
+
@state.stack.should == [5, 0, []]
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The commit instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:commit]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "discards the alternate stack info pushed by a choice instruction" do
|
11
|
+
@state.stack << 3 << [] << 1 << 2
|
12
|
+
@insn[@state, 5]
|
13
|
+
@state.stack.should == [3]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the machine IP to the value of the argument" do
|
17
|
+
@state.stack << [] << 1 << 2
|
18
|
+
@insn[@state, 5]
|
19
|
+
@state.ip.should == 5
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The fail instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:fail]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "does not clear the failure if the stack is empty" do
|
11
|
+
@state.failure
|
12
|
+
@state.stack.should be_empty
|
13
|
+
@insn[@state]
|
14
|
+
@state.failure?.should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "does not clear the failure state if the stack only contains return address labels" do
|
18
|
+
@state.failure
|
19
|
+
@state.stack << 1 << 2 << 3
|
20
|
+
@insn[@state]
|
21
|
+
@state.stack.should be_empty
|
22
|
+
@state.failure?.should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "clears the failure state and assigns the IP, subject index, and captures list to the values on the stack" do
|
26
|
+
@state.failure
|
27
|
+
@state.stack << 1 << 2 << 3 << [] << 4
|
28
|
+
@insn[@state]
|
29
|
+
@state.stack.should == [1]
|
30
|
+
@state.failure?.should be_false
|
31
|
+
@state.ip.should == 2
|
32
|
+
@state.index.should == 3
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The jump instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:jump]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sets the IP to the value of the argument" do
|
11
|
+
@state.ip.should == 0
|
12
|
+
@insn[@state, 5]
|
13
|
+
@state.ip.should == 5
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
require 'pegarus/machine'
|
3
|
+
|
4
|
+
describe "The return instruction" do
|
5
|
+
before :each do
|
6
|
+
@state = Pegarus::Machine::State.new ""
|
7
|
+
_, @insn = Pegarus::Machine::Instructions[:return]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sets the machine IP to the value popped from the stack" do
|
11
|
+
@state.stack << 5
|
12
|
+
@insn[@state]
|
13
|
+
@state.stack.should == []
|
14
|
+
@state.ip.should == 5
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe :ast_any, :shared => true do
|
2
|
+
it "returns nil when the subject is empty" do
|
3
|
+
Pegarus.pattern(1).match("").should be_nil
|
4
|
+
end
|
5
|
+
|
6
|
+
it "returns nil if there are not N characters to match in the subject" do
|
7
|
+
Pegarus.pattern(3).match("ab").should be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns the index of the character following the matched substring" do
|
11
|
+
Pegarus.pattern(3).match("abcd").should == 3
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe :ast_character, :shared => true do
|
2
|
+
it "returns nil when the subject is empty" do
|
3
|
+
Pegarus.pattern("a").match("").should be_nil
|
4
|
+
end
|
5
|
+
|
6
|
+
it "returns nil when the subject does not match completely" do
|
7
|
+
Pegarus.pattern("abc").match("abde").should be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns the index of the character following the matched substring" do
|
11
|
+
Pegarus.pattern("abc").match("abcde").should == 3
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns 0 when pattern is empty" do
|
15
|
+
Pegarus.pattern("").match("abc").should == 0
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe :ast_choice, :shared => true do
|
2
|
+
it "returns nil if none of the patterns match" do
|
3
|
+
pat = Pegarus.pattern("a") / Pegarus.pattern("b")
|
4
|
+
pat.match("c").should be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
it "matches the first pattern if both match" do
|
8
|
+
pat = Pegarus.pattern("aaa") / Pegarus.pattern("a")
|
9
|
+
pat.match("aaa").should == 3
|
10
|
+
end
|
11
|
+
|
12
|
+
it "matches the second pattern if the first does not match" do
|
13
|
+
pat = Pegarus.pattern("a") / Pegarus.pattern("bc")
|
14
|
+
pat.match("bc").should == 2
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe :ast_concatenation, :shared => true do
|
2
|
+
it "returns nil if the first pattern does not match" do
|
3
|
+
pat = Pegarus.pattern(1) + Pegarus.pattern("a")
|
4
|
+
pat.match("").should be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns nil if the second pattern does not match" do
|
8
|
+
pat = Pegarus.pattern(1) + Pegarus.pattern("a")
|
9
|
+
pat.match("ab").should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns the index of the character following the matched substring" do
|
13
|
+
pat = Pegarus.pattern(1) + Pegarus.pattern("ac")
|
14
|
+
pat.match("aacbde").should == 3
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe :ast_if, :shared => true do
|
2
|
+
it "returns nil if the first pattern does not match" do
|
3
|
+
pat = Pegarus.pattern(1) + +Pegarus.pattern("a")
|
4
|
+
pat.match("").should be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns nil if the second pattern does not match" do
|
8
|
+
pat = Pegarus.pattern(1) + +Pegarus.pattern("c")
|
9
|
+
pat.match("ab").should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns the index of the character following the matched substring" do
|
13
|
+
pat = Pegarus.pattern(1) + +Pegarus.pattern("ac")
|
14
|
+
pat.match("aacbde").should == 1
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
describe :ast_unless, :shared => true do
|
2
|
+
it "returns nil if the first pattern does not match" do
|
3
|
+
pat = Pegarus.pattern(1) + -Pegarus.pattern("a")
|
4
|
+
pat.match("").should be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns nil if the second pattern match" do
|
8
|
+
pat = Pegarus.pattern(1) + -Pegarus.pattern("b")
|
9
|
+
pat.match("ab").should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns the index of the character following the matched substring" do
|
13
|
+
pat = Pegarus.pattern(1) + -Pegarus.pattern("xx")
|
14
|
+
pat.match("aacbde").should == 1
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$: << File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'pegarus'
|
4
|
+
|
5
|
+
case ENV["PEGARUS_MACHINE"]
|
6
|
+
when "vm"
|
7
|
+
require 'pegarus/machine'
|
8
|
+
Pegarus::Pattern.machine Pegarus::ParsingMachine
|
9
|
+
when "xjit"
|
10
|
+
require 'pegarus/rubinius'
|
11
|
+
Pegarus::Pattern.machine Pegarus::RubiniusJIT
|
12
|
+
end
|