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