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
@@ -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
|