pegarus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/LICENSE +22 -0
  2. data/README +24 -0
  3. data/Rakefile +70 -0
  4. data/lib/pegarus/ast/always.rb +7 -0
  5. data/lib/pegarus/ast/any.rb +13 -0
  6. data/lib/pegarus/ast/any_range.rb +13 -0
  7. data/lib/pegarus/ast/character.rb +13 -0
  8. data/lib/pegarus/ast/character_range.rb +13 -0
  9. data/lib/pegarus/ast/choice.rb +7 -0
  10. data/lib/pegarus/ast/concatenation.rb +7 -0
  11. data/lib/pegarus/ast/difference.rb +7 -0
  12. data/lib/pegarus/ast/grammar.rb +56 -0
  13. data/lib/pegarus/ast/if.rb +9 -0
  14. data/lib/pegarus/ast/never.rb +7 -0
  15. data/lib/pegarus/ast/pattern.rb +127 -0
  16. data/lib/pegarus/ast/product.rb +12 -0
  17. data/lib/pegarus/ast/set.rb +13 -0
  18. data/lib/pegarus/ast/unless.rb +9 -0
  19. data/lib/pegarus/ast/variable.rb +15 -0
  20. data/lib/pegarus/ast.rb +16 -0
  21. data/lib/pegarus/compatibility.rb +25 -0
  22. data/lib/pegarus/evaluator.rb +93 -0
  23. data/lib/pegarus/machine/compiler.rb +18 -0
  24. data/lib/pegarus/machine/generator.rb +8 -0
  25. data/lib/pegarus/machine/instructions.rb +65 -0
  26. data/lib/pegarus/machine/interpreter.rb +31 -0
  27. data/lib/pegarus/machine/state.rb +29 -0
  28. data/lib/pegarus/machine.rb +15 -0
  29. data/lib/pegarus/parser/parse_error.rb +3 -0
  30. data/lib/pegarus/parser.rb +1 -0
  31. data/lib/pegarus/rubinius/compiler.rb +220 -0
  32. data/lib/pegarus/rubinius/generator.rb +48 -0
  33. data/lib/pegarus/rubinius.rb +4 -0
  34. data/lib/pegarus/version.rb +3 -0
  35. data/lib/pegarus.rb +3 -0
  36. data/spec/ast/choice_spec.rb +9 -0
  37. data/spec/ast/concatenation_spec.rb +9 -0
  38. data/spec/ast/difference_spec.rb +9 -0
  39. data/spec/ast/grammar_spec.rb +54 -0
  40. data/spec/ast/if_spec.rb +8 -0
  41. data/spec/ast/pattern_spec.rb +123 -0
  42. data/spec/ast/product_spec.rb +28 -0
  43. data/spec/ast/unless_spec.rb +8 -0
  44. data/spec/ast/variable_spec.rb +4 -0
  45. data/spec/custom/guards/engine.rb +27 -0
  46. data/spec/machine/instructions/call_spec.rb +21 -0
  47. data/spec/machine/instructions/capture_spec.rb +15 -0
  48. data/spec/machine/instructions/char_spec.rb +34 -0
  49. data/spec/machine/instructions/choice_spec.rb +15 -0
  50. data/spec/machine/instructions/commit_spec.rb +21 -0
  51. data/spec/machine/instructions/fail_spec.rb +34 -0
  52. data/spec/machine/instructions/jump_spec.rb +15 -0
  53. data/spec/machine/instructions/return_spec.rb +16 -0
  54. data/spec/matching/evaluator/any_spec.rb +6 -0
  55. data/spec/matching/evaluator/character_spec.rb +6 -0
  56. data/spec/matching/evaluator/choice_spec.rb +6 -0
  57. data/spec/matching/evaluator/concatenation_spec.rb +6 -0
  58. data/spec/matching/evaluator/difference_spec.rb +6 -0
  59. data/spec/matching/evaluator/if_spec.rb +6 -0
  60. data/spec/matching/evaluator/product_spec.rb +6 -0
  61. data/spec/matching/evaluator/setup.rb +4 -0
  62. data/spec/matching/evaluator/unless_spec.rb +6 -0
  63. data/spec/matching/machine/any_spec.rb +6 -0
  64. data/spec/matching/machine/character_spec.rb +6 -0
  65. data/spec/matching/machine/choice_spec.rb +6 -0
  66. data/spec/matching/machine/concatenation_spec.rb +6 -0
  67. data/spec/matching/machine/difference_spec.rb +6 -0
  68. data/spec/matching/machine/if_spec.rb +6 -0
  69. data/spec/matching/machine/product_spec.rb +6 -0
  70. data/spec/matching/machine/setup.rb +4 -0
  71. data/spec/matching/machine/unless_spec.rb +6 -0
  72. data/spec/matching/rubinius/any_spec.rb +8 -0
  73. data/spec/matching/rubinius/character_spec.rb +8 -0
  74. data/spec/matching/rubinius/choice_spec.rb +8 -0
  75. data/spec/matching/rubinius/concatenation_spec.rb +8 -0
  76. data/spec/matching/rubinius/difference_spec.rb +8 -0
  77. data/spec/matching/rubinius/if_spec.rb +8 -0
  78. data/spec/matching/rubinius/product_spec.rb +8 -0
  79. data/spec/matching/rubinius/setup.rb +4 -0
  80. data/spec/matching/rubinius/unless_spec.rb +8 -0
  81. data/spec/matching/shared/any.rb +13 -0
  82. data/spec/matching/shared/character.rb +17 -0
  83. data/spec/matching/shared/choice.rb +16 -0
  84. data/spec/matching/shared/concatenation.rb +16 -0
  85. data/spec/matching/shared/difference.rb +2 -0
  86. data/spec/matching/shared/if.rb +16 -0
  87. data/spec/matching/shared/product.rb +2 -0
  88. data/spec/matching/shared/unless.rb +16 -0
  89. data/spec/spec_helper.rb +12 -0
  90. 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,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/any'
3
+
4
+ describe "Any#match" do
5
+ it_should_behave_like :ast_any
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/character'
3
+
4
+ describe "Character#match" do
5
+ it_should_behave_like :ast_character
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/choice'
3
+
4
+ describe "Choice#match" do
5
+ it_should_behave_like :ast_choice
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/concatenation'
3
+
4
+ describe "Concatenation#match" do
5
+ it_should_behave_like :ast_concatenation
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/difference'
3
+
4
+ describe "Difference#match" do
5
+ it_should_behave_like :ast_difference
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/if'
3
+
4
+ describe "If#match" do
5
+ it_should_behave_like :ast_if
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/product'
3
+
4
+ describe "Product#match" do
5
+ it_should_behave_like :ast_product
6
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec/spec_helper'
2
+ require 'pegarus/evaluator'
3
+
4
+ Pegarus::Pattern.select_engine Pegarus::Evaluator
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/evaluator/setup'
2
+ require 'spec/matching/shared/unless'
3
+
4
+ describe "Unless#match" do
5
+ it_should_behave_like :ast_unless
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/any'
3
+
4
+ describe "Any#match" do
5
+ it_should_behave_like :ast_any
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/character'
3
+
4
+ describe "Character#match" do
5
+ it_should_behave_like :ast_character
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/choice'
3
+
4
+ describe "Choice#match" do
5
+ it_should_behave_like :ast_choice
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/concatenation'
3
+
4
+ describe "Concatenation#match" do
5
+ it_should_behave_like :ast_concatenation
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/difference'
3
+
4
+ describe "Difference#match" do
5
+ it_should_behave_like :ast_difference
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/if'
3
+
4
+ describe "If#match" do
5
+ it_should_behave_like :ast_if
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/product'
3
+
4
+ describe "Product#match" do
5
+ it_should_behave_like :ast_product
6
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec/spec_helper'
2
+ require 'pegarus/machine'
3
+
4
+ Pegarus::Pattern.select_engine Pegarus::Machine
@@ -0,0 +1,6 @@
1
+ require 'spec/matching/machine/setup'
2
+ require 'spec/matching/shared/unless'
3
+
4
+ describe "Unless#match" do
5
+ it_should_behave_like :ast_unless
6
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/any'
4
+
5
+ describe "Any#match" do
6
+ it_should_behave_like :ast_any
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/character'
4
+
5
+ describe "Character#match" do
6
+ it_should_behave_like :ast_character
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/choice'
4
+
5
+ describe "Choice#match" do
6
+ it_should_behave_like :ast_choice
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/concatenation'
4
+
5
+ describe "Concatenation#match" do
6
+ it_should_behave_like :ast_concatenation
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/difference'
4
+
5
+ describe "Difference#match" do
6
+ it_should_behave_like :ast_difference
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/if'
4
+
5
+ describe "If#match" do
6
+ it_should_behave_like :ast_if
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/product'
4
+
5
+ describe "Product#match" do
6
+ it_should_behave_like :ast_product
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec/spec_helper'
2
+ require 'pegarus/rubinius'
3
+
4
+ Pegarus::Pattern.select_engine Pegarus::Rubinius
@@ -0,0 +1,8 @@
1
+ engine_is :rbx do
2
+ require 'spec/matching/rubinius/setup'
3
+ require 'spec/matching/shared/unless'
4
+
5
+ describe "Unless#match" do
6
+ it_should_behave_like :ast_unless
7
+ end
8
+ 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,2 @@
1
+ describe :ast_difference, :shared => true do
2
+ 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,2 @@
1
+ describe :ast_product, :shared => true do
2
+ 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
@@ -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