sbyc 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 (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
+