sbyc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/LICENCE.textile +12 -0
  2. data/README.textile +44 -0
  3. data/lib/sbyc.rb +14 -0
  4. data/lib/sbyc/codetree.rb +82 -0
  5. data/lib/sbyc/codetree/ast_node.rb +101 -0
  6. data/lib/sbyc/codetree/eval.rb +3 -0
  7. data/lib/sbyc/codetree/eval/ast_node_ext.rb +38 -0
  8. data/lib/sbyc/codetree/eval/functional_eval.rb +36 -0
  9. data/lib/sbyc/codetree/eval/object_eval.rb +36 -0
  10. data/lib/sbyc/codetree/matching.rb +3 -0
  11. data/lib/sbyc/codetree/matching/ast_node_ext.rb +14 -0
  12. data/lib/sbyc/codetree/matching/match_data.rb +30 -0
  13. data/lib/sbyc/codetree/matching/matcher.rb +83 -0
  14. data/lib/sbyc/codetree/proc_parser.rb +91 -0
  15. data/lib/sbyc/codetree/producing.rb +1 -0
  16. data/lib/sbyc/codetree/producing/producer.rb +68 -0
  17. data/lib/sbyc/codetree/rewriting.rb +4 -0
  18. data/lib/sbyc/codetree/rewriting/class_methods.rb +15 -0
  19. data/lib/sbyc/codetree/rewriting/compiler.rb +28 -0
  20. data/lib/sbyc/codetree/rewriting/instance_methods.rb +92 -0
  21. data/lib/sbyc/codetree/rewriting/match.rb +59 -0
  22. data/test/spec/documentation/codetree/production.spec +59 -0
  23. data/test/spec/documentation/readme/assumptions.spec +33 -0
  24. data/test/spec/documentation/readme/functional_evaluation.spec +29 -0
  25. data/test/spec/documentation/readme/object_evaluation.spec +17 -0
  26. data/test/spec/documentation/readme/rewriting.spec +60 -0
  27. data/test/spec/documentation/readme/semantics.spec +21 -0
  28. data/test/spec/documentation/readme/synopsis.spec +27 -0
  29. data/test/spec/documentation/readme/syntax.spec +26 -0
  30. data/test/spec/spec_helper.rb +13 -0
  31. data/test/spec/test_all.rb +6 -0
  32. data/test/spec/unit/sbyc/codetree/ast_node/coerce.spec +60 -0
  33. data/test/spec/unit/sbyc/codetree/ast_node/equality.spec +75 -0
  34. data/test/spec/unit/sbyc/codetree/ast_node/inspect.spec +23 -0
  35. data/test/spec/unit/sbyc/codetree/ast_node/literal.spec +15 -0
  36. data/test/spec/unit/sbyc/codetree/ast_node/to_a.spec +27 -0
  37. data/test/spec/unit/sbyc/codetree/ast_node/to_s.spec +23 -0
  38. data/test/spec/unit/sbyc/codetree/ast_node/visit.spec +34 -0
  39. data/test/spec/unit/sbyc/codetree/eval/functional_compile.spec +30 -0
  40. data/test/spec/unit/sbyc/codetree/eval/functional_eval.spec +34 -0
  41. data/test/spec/unit/sbyc/codetree/eval/functional_proc.spec +36 -0
  42. data/test/spec/unit/sbyc/codetree/eval/object_compile.spec +36 -0
  43. data/test/spec/unit/sbyc/codetree/eval/object_eval.spec +38 -0
  44. data/test/spec/unit/sbyc/codetree/eval/object_proc.spec +36 -0
  45. data/test/spec/unit/sbyc/codetree/matching/matcher/args_match.spec +91 -0
  46. data/test/spec/unit/sbyc/codetree/matching/matcher/do_match.spec +39 -0
  47. data/test/spec/unit/sbyc/codetree/matching/matcher/function_match.spec +45 -0
  48. data/test/spec/unit/sbyc/codetree/matching/matcher/match.spec +64 -0
  49. data/test/spec/unit/sbyc/codetree/proc_parser/expr.spec +20 -0
  50. data/test/spec/unit/sbyc/codetree/proc_parser/parse.spec +83 -0
  51. data/test/spec/unit/sbyc/codetree/producing/producer.spec +31 -0
  52. data/test/spec/unit/sbyc/codetree/producing/producer/apply_args_conventions.spec +60 -0
  53. data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/apply_args_conventions.spec +60 -0
  54. data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/node.spec +19 -0
  55. data/test/spec/unit/sbyc/codetree/rewriting/instance_methods/rewrite.spec +76 -0
  56. data/test/spec/unit/sbyc/codetree/rewriting/match/apply.spec +23 -0
  57. data/test/spec/unit/sbyc/codetree/rewriting/match/coerce.spec +48 -0
  58. data/test/spec/unit/sbyc/codetree/rewriting/match/matches.spec +27 -0
  59. metadata +129 -0
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#functional_compile" do
4
+
5
+ context('when called on a leaf node') do
6
+ let(:node) { CodeTree::expr{ 12 } }
7
+ subject{ node.functional_compile }
8
+ it { should == "12" }
9
+ end
10
+
11
+ context('when called on a ?') do
12
+ let(:node) { CodeTree::expr{ x } }
13
+ subject{ node.functional_compile }
14
+ it { should == "scope[:x]" }
15
+ end
16
+
17
+ context('when called on a object-like expression') do
18
+ let(:node) { CodeTree::expr{ (say x, "Hello") } }
19
+ subject{ node.functional_compile }
20
+ it { should == 'receiver.say(scope[:x], "Hello")' }
21
+ end
22
+
23
+ context('when called with specific arguments') do
24
+ let(:node) { CodeTree::expr{ (say x, "Hello") } }
25
+ subject{ node.functional_compile('r', 'hash', 'get') }
26
+ it { should == 'r.say(hash.get(:x), "Hello")' }
27
+ end
28
+
29
+ end
30
+
@@ -0,0 +1,34 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#functional_eval" do
4
+
5
+ context('when called on a leaf node') do
6
+ let(:node) { CodeTree::expr{ 12 } }
7
+ subject{ node.functional_eval(Kernel, { }) }
8
+ it { should == 12 }
9
+ end
10
+
11
+ context('when called on a ?') do
12
+ let(:node) { CodeTree::expr{ x } }
13
+ subject{ node.functional_eval(Kernel, :x => 12) }
14
+ it { should == 12 }
15
+ end
16
+
17
+ context('when called on a object-like expression') do
18
+ let(:node) { CodeTree::expr{ (say x, "You") } }
19
+ let(:master) { x = Object.new; def x.say(*args); args.join(" "); end; x}
20
+
21
+ subject{ node.functional_eval(master, :x => "hello") }
22
+
23
+ it { subject.should == "hello You" }
24
+ end
25
+
26
+ context('when called on a object-like expression with specific scope method') do
27
+ let(:node) { CodeTree::expr{ (say x, "You") } }
28
+ let(:master) { x = Object.new; def x.say(*args); args.join(" "); end; x}
29
+ subject{ node.functional_eval(master, {:x => "hello"}, :fetch) }
30
+ it { subject.should == "hello You" }
31
+ end
32
+
33
+ end
34
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#functional_proc" do
4
+
5
+ let(:receiver) {
6
+ o = Object.new
7
+ def o.upcase(x); x.upcase; end
8
+ o
9
+ }
10
+
11
+ context('when called on a leaf node') do
12
+ let(:node) { CodeTree::expr{ 12 } }
13
+ subject{ node.functional_proc.call(nil, nil) }
14
+ it { should == 12 }
15
+ end
16
+
17
+ context('when called on a ?') do
18
+ let(:node) { CodeTree::expr{ x } }
19
+ subject{ node.functional_proc.call(receiver, :x => "hello") }
20
+ it { should == "hello" }
21
+ end
22
+
23
+ context('when called on a object-like expression') do
24
+ let(:node) { CodeTree::expr{ (upcase x) } }
25
+ subject{ node.functional_proc.call(receiver, :x => "hello") }
26
+ it { should == 'HELLO' }
27
+ end
28
+
29
+ context('when called with specific arguments') do
30
+ let(:node) { CodeTree::expr{ (upcase x) } }
31
+ subject{ node.functional_proc(:fetch).call(receiver, :x => "hello") }
32
+ it { should == 'HELLO' }
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#object_compile" do
4
+
5
+ context('when called on a leaf node, through coercion') do
6
+ let(:node) { CodeTree::expr{ 12 } }
7
+ subject{ node.object_compile }
8
+ it { should == "12" }
9
+ end
10
+
11
+ context('when called on a ?') do
12
+ let(:node) { CodeTree::expr{ x } }
13
+ subject{ node.object_compile }
14
+ it { should == "scope[:x]" }
15
+ end
16
+
17
+ context('when called on an expression') do
18
+ let(:node) { CodeTree::expr{ x + z } }
19
+ subject{ node.object_compile }
20
+ it { should == "scope[:x].+(scope[:z])" }
21
+ end
22
+
23
+ context('when called on a object-like expression') do
24
+ let(:node) { CodeTree::expr{ x.say_hello } }
25
+ subject{ node.object_compile }
26
+ it { should == "scope[:x].say_hello()" }
27
+ end
28
+
29
+ context('when called with specific arguments') do
30
+ let(:node) { CodeTree::expr{ x.say_hello } }
31
+ subject{ node.object_compile('hash', :get) }
32
+ it { should == "hash.get(:x).say_hello()"}
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,38 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#object_eval" do
4
+
5
+ context('when called on a leaf node, through coercion') do
6
+ let(:node) { CodeTree::expr{ 12 } }
7
+ subject{ node.object_eval }
8
+ it { should == 12 }
9
+ end
10
+
11
+ context('when called on a ?') do
12
+ let(:node) { CodeTree::expr{ x } }
13
+ subject{ node.object_eval(:x => 12) }
14
+ it { should == 12 }
15
+ end
16
+
17
+ context('when called on an expression') do
18
+ let(:node) { CodeTree::expr{ x + z } }
19
+ subject{ node.object_eval(:x => 12, :z => 15) }
20
+ it { should == 27 }
21
+ end
22
+
23
+ context('when called on a object-like expression') do
24
+ let(:node) { CodeTree::expr{ x.say_hello } }
25
+ let(:twel) { x = Object.new; def x.say_hello(); "hello"; end; x}
26
+ subject{ node.object_eval(:x => twel) }
27
+ it { should == "hello" }
28
+ end
29
+
30
+ context('when called on a object-like expression and specific scope method') do
31
+ let(:node) { CodeTree::expr{ x.say_hello } }
32
+ let(:twel) { x = Object.new; def x.say_hello(); "hello"; end; x}
33
+ subject{ node.object_eval({:x => twel}, :fetch) }
34
+ it { should == "hello" }
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#object_proc" do
4
+
5
+ context('when called on a leaf node, through coercion') do
6
+ let(:node) { CodeTree::expr{ 12 } }
7
+ subject{ node.object_proc.call(nil) }
8
+ it { should == 12 }
9
+ end
10
+
11
+ context('when called on a ?') do
12
+ let(:node) { CodeTree::expr{ x } }
13
+ subject{ node.object_proc.call(:x => 12) }
14
+ it { should == 12 }
15
+ end
16
+
17
+ context('when called on an expression') do
18
+ let(:node) { CodeTree::expr{ x + z } }
19
+ subject{ node.object_proc.call(:x => 12, :z => 15) }
20
+ it { should == 27 }
21
+ end
22
+
23
+ context('when called on a object-like expression') do
24
+ let(:node) { CodeTree::expr{ x.upcase } }
25
+ subject{ node.object_proc.call(:x => "teller") }
26
+ it { should == "TELLER" }
27
+ end
28
+
29
+ context('when called with specific arguments') do
30
+ let(:node) { CodeTree::expr{ x.upcase } }
31
+ subject{ node.object_proc(:fetch).call(:x => "teller") }
32
+ it { should == "TELLER"}
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,91 @@
1
+ require File.expand_path('../../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::Matcher#args_match" do
4
+
5
+ let(:imatch) { CodeTree::Matcher.new nil }
6
+
7
+ context "when called with a capture match" do
8
+ let(:matcher) { CodeTree::parse{ x } }
9
+ let(:matched) { CodeTree::parse{ 12 } }
10
+ let(:match_data) { { } }
11
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
12
+
13
+ specify {
14
+ subject.should be_true
15
+ match_data[:x].should == matched
16
+ }
17
+ end
18
+
19
+ context "when called with a literal match" do
20
+ let(:matcher) { CodeTree::parse{ 12 } }
21
+ let(:matched) { CodeTree::parse{ 12 } }
22
+ let(:match_data) { { } }
23
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
24
+
25
+ specify { subject.should be_true }
26
+ end
27
+
28
+ context "when called with a literal no-match" do
29
+ let(:matcher) { CodeTree::parse{ 13 } }
30
+ let(:matched) { CodeTree::parse{ 12 } }
31
+ let(:match_data) { { } }
32
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
33
+
34
+ specify { subject.should be_false }
35
+ end
36
+
37
+ context "when called with a recursive match" do
38
+ let(:matcher) { CodeTree::parse{ (match :hello, x) } }
39
+ let(:matched) { CodeTree::parse{ (hello "You") } }
40
+ let(:match_data) { { } }
41
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
42
+
43
+ specify {
44
+ subject.should be_true
45
+ match_data[:x].should == CodeTree::parse{ "You" }
46
+ }
47
+ end
48
+
49
+ context "when called with a recursive match with varargs and one arg" do
50
+ let(:matcher) { CodeTree::parse{ (match :hello, x[]) } }
51
+ let(:matched) { CodeTree::parse{ (hello "You") } }
52
+ let(:match_data) { { } }
53
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
54
+
55
+ specify {
56
+ subject.should be_true
57
+ match_data[:x].should == [ CodeTree::parse{ "You"} ]
58
+ }
59
+ end
60
+
61
+ context "when called with a recursive match with varargs and many args" do
62
+ let(:matcher) { CodeTree::parse{ (match :hello, x[]) } }
63
+ let(:matched) { CodeTree::parse{ (hello "You", "and", 'world') } }
64
+ let(:match_data) { { } }
65
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
66
+
67
+ specify {
68
+ subject.should be_true
69
+ match_data[:x].should == [ CodeTree::parse{ "You"}, CodeTree::parse{ "and"}, CodeTree::parse{ "world"} ]
70
+ }
71
+ end
72
+
73
+ context "when called with a recursive no-match with empty varargs" do
74
+ let(:matcher) { CodeTree::parse{ (match :hello, x, y[]) } }
75
+ let(:matched) { CodeTree::parse{ (hello "You") } }
76
+ let(:match_data) { { } }
77
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
78
+
79
+ specify { subject.should be_false }
80
+ end
81
+
82
+ context "when called with a recursive no-match" do
83
+ let(:matcher) { CodeTree::parse{ (match :hello, "world") } }
84
+ let(:matched) { CodeTree::parse{ (hello 12) } }
85
+ let(:match_data) { { } }
86
+ let(:subject) { imatch.args_match([ matcher ], [ matched ], match_data)}
87
+
88
+ specify { subject.should be_false }
89
+ end
90
+
91
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::Matcher#match" do
4
+
5
+ context 'When capture are provided' do
6
+ let(:matcher) { CodeTree::parse{ (match :hello, (match :whos, x, y)) } }
7
+ let(:matched) { CodeTree::parse{ (hello (whos "world", "others")) } }
8
+ let(:subject) { CodeTree::Matcher.new(matcher) =~ matched }
9
+ specify {
10
+ subject[:x].literal.should == "world"
11
+ subject[:y].literal.should == "others"
12
+ }
13
+ end
14
+
15
+ context "When applying correct matches" do
16
+ [
17
+ [CodeTree::parse{ (match :hello, "world") }, CodeTree::parse{ (hello "world") }],
18
+ [CodeTree::parse{ (match :hello, x) }, CodeTree::parse{ (hello "world") }],
19
+ [CodeTree::parse{ (match :hello, x, y, z) }, CodeTree::parse{ (hello "world", "and", "others") }],
20
+ [CodeTree::parse{ (match :hello, (match :world, x)) }, CodeTree::parse{ (hello (world "I")) }],
21
+ ].each do |matcher, matched|
22
+ let(:subject){ CodeTree::Matcher.new(matcher) =~ matched }
23
+ it { should_not be_nil }
24
+ end
25
+ end
26
+
27
+ context "When applying incorrect matches" do
28
+ [
29
+ [CodeTree::parse{ (match :hello, "world") }, CodeTree::parse{ (hello 12) }],
30
+ [CodeTree::parse{ (match :hello, "world") }, CodeTree::parse{ (hello "world", "and", "others") }],
31
+ [CodeTree::parse{ (match :hello, (match :world, x)) }, CodeTree::parse{ (hello "world") }],
32
+ ].each do |matcher, matched|
33
+ let(:subject){ CodeTree::Matcher.new(matcher) =~ matched }
34
+ it { should be_nil }
35
+ end
36
+ end
37
+
38
+ end
39
+
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::Matcher#function_match" do
4
+
5
+ context "called with a literal match" do
6
+ let(:match) { CodeTree::parse{ (match :hello) } }
7
+ let(:victim) { CodeTree::parse{ (hello "world") } }
8
+ let(:match_data) { Hash.new }
9
+
10
+ subject{ ::CodeTree::Matcher.new(match).function_match(match, victim, match_data) }
11
+
12
+ specify {
13
+ subject.should == true
14
+ match_data.should == {}
15
+ }
16
+ end
17
+
18
+ context "called with a capture match" do
19
+ let(:match) { CodeTree::parse{ (match something) } }
20
+ let(:victim) { CodeTree::parse{ (hello "world") } }
21
+ let(:match_data) { Hash.new }
22
+
23
+ subject{ ::CodeTree::Matcher.new(match).function_match(match, victim, match_data) }
24
+
25
+ specify {
26
+ subject.should == true
27
+ match_data.should == {:something => :hello}
28
+ }
29
+ end
30
+
31
+ context "called without match" do
32
+ let(:match) { CodeTree::parse{ (match :hello) } }
33
+ let(:victim) { CodeTree::parse{ (i "world") } }
34
+ let(:match_data) { Hash.new }
35
+
36
+ subject{ ::CodeTree::Matcher.new(match).function_match(match, victim, match_data) }
37
+
38
+ specify {
39
+ subject.should == false
40
+ match_data.should == {}
41
+ }
42
+ end
43
+
44
+ end
45
+
@@ -0,0 +1,64 @@
1
+ require File.expand_path('../../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::Matcher#match" do
4
+
5
+ context "when called on something that matches" do
6
+ let(:matcher) { CodeTree::matcher{ (match :say, x) } }
7
+ let(:matched) { CodeTree::parse { (say "hello") } }
8
+ subject{ matcher =~ matched }
9
+ it { should_not be_nil }
10
+ specify{ subject[:x].should == CodeTree::parse{"hello"} }
11
+ end
12
+
13
+ context "when called on something that does not match" do
14
+ let(:matcher) { CodeTree::matcher{ (match :say, x) } }
15
+ let(:matched) { CodeTree::parse { (nosay "hello") } }
16
+ subject{ matcher =~ matched }
17
+ it { should be_nil }
18
+ end
19
+
20
+ context "a generic matcher" do
21
+ let(:matcher) { CodeTree::matcher{ (match x, y[]) } }
22
+
23
+ context 'against a ruby object' do
24
+ let(:expr) { 12 }
25
+ subject { matcher =~ expr }
26
+ it { should be_nil }
27
+ end
28
+
29
+ context 'against a literal' do
30
+ let(:expr) { CodeTree::parse{ 12 } }
31
+ subject { matcher =~ expr }
32
+ it { should_not be_nil }
33
+ specify { subject[:x].should == :_ }
34
+ specify { subject[:y].should == [12] }
35
+ end
36
+
37
+ context 'against a variable' do
38
+ let(:expr) { CodeTree::parse{ var } }
39
+ subject { matcher =~ expr }
40
+ it { should_not be_nil }
41
+ specify { subject[:x].should == :'?' }
42
+ specify { subject[:y].should == [ CodeTree::parse{ :var }] }
43
+ end
44
+
45
+ context 'against a function with one literal argument' do
46
+ let(:expr) { CodeTree::parse{ (func "a") } }
47
+ subject { matcher =~ expr }
48
+ it { should_not be_nil }
49
+ specify { subject[:x].should == :func }
50
+ specify { subject[:y].should == [ CodeTree::parse{ "a" } ] }
51
+ end
52
+
53
+ context 'against a function with two arguments' do
54
+ let(:expr) { CodeTree::parse{ (func "a", b) } }
55
+ subject { matcher =~ expr }
56
+ it { should_not be_nil }
57
+ specify { subject[:x].should == :func }
58
+ specify { subject[:y].should == [ CodeTree::parse{ "a" }, CodeTree::parse{ b } ] }
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+