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,29 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # object-evaluation section" do
4
+
5
+ let(:expr){ ::CodeTree::parse{ (display (concat x, y)) } }
6
+
7
+ describe('what is said about the ast') do
8
+ subject{ expr.to_s }
9
+ it { should == "(display (concat x, y))" }
10
+ end
11
+
12
+ describe("what is said about apply") do
13
+ let(:receiver) {
14
+ r = Object.new
15
+ r.instance_eval <<-EOF
16
+ def concat(*args)
17
+ args.join
18
+ end
19
+ def display(arg)
20
+ arg
21
+ end
22
+ EOF
23
+ r
24
+ }
25
+ subject{ expr.apply(receiver, :x => 3, :y => 25) }
26
+ it { should == "325" }
27
+ end
28
+
29
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # object-evaluation section" do
4
+
5
+ let(:expr){ CodeTree::parse{ (x + y).to_s } }
6
+
7
+ describe('what is said about the ast') do
8
+ subject{ expr.to_s }
9
+ it { should == "(to_s (+ x, y))" }
10
+ end
11
+
12
+ describe("what is said about eval") do
13
+ subject{ expr.eval(:x => 3, :y => 25) }
14
+ it { should == "28" }
15
+ end
16
+
17
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # rewriting section" do
4
+
5
+ let(:code) { lambda{ (concat "hello ", who, (times "!", 3)) } }
6
+ let(:ast) { CodeTree::parse(code) }
7
+
8
+ describe('What is said about the ast') do
9
+ subject{ ast.inspect }
10
+ it { should == '(concat (_ "hello "), (? (_ :who)), (times (_ "!"), (_ 3)))' }
11
+ end
12
+
13
+ describe("What is said about the evaluation") do
14
+ let(:rewriter) { CodeTree::rewriter {|r|
15
+ r.rule(:concat) {|r, node, *children| r.apply(children).join("") }
16
+ r.rule(:capitalize) {|r, node, who| r.apply(who).capitalize }
17
+ r.rule(:times) {|r, node, who, times| r.apply(who) * r.apply(times) }
18
+ r.rule(:'?') {|r, node, what| r.scope[r.apply(what)] }
19
+ r.rule(:'_') {|r, node, literal| literal }
20
+ }}
21
+
22
+ subject { rewriter.rewrite(ast, :who => "You") }
23
+
24
+ it { should == "hello You!!!" }
25
+ end
26
+
27
+ describe("What is said about the code generation") do
28
+ let(:rewriter) { CodeTree::rewriter {|r|
29
+ r.rule(:concat) {|r, node, *children| r.apply(children).join(" + ") }
30
+ r.rule(:capitalize) {|r, node, who| "#{r.apply(who)}.capitalize()" }
31
+ r.rule(:times) {|r, node, who, times| "(#{r.apply(who)} * #{r.apply(times)})" }
32
+ r.rule(:'?') {|r, node, what| "scope[#{r.apply(what)}]" }
33
+ r.rule(:'_') {|r, node, literal| literal.inspect }
34
+ }}
35
+
36
+ subject { rewriter.rewrite(ast) }
37
+
38
+ it { should == '"hello " + scope[:who] + ("!" * 3)' }
39
+ end
40
+
41
+ describe("What is said about the code tree rewriting") do
42
+ let(:rewriter) { CodeTree::rewriter {|r|
43
+ r.rule(:concat) {|r, node, left, right, *residual|
44
+ rewrited = r.node(:+, r.apply(left), r.apply(right))
45
+ if residual.empty?
46
+ rewrited
47
+ else
48
+ r.apply(r.node(:concat, [ rewrited ] + residual))
49
+ end
50
+ }
51
+ r.rule(:times) {|r, node, *children| r.node(:*, r.apply(children)) }
52
+ r.rule(r.ANY) {|r, node, *children| r.node(node.function, children) }
53
+ }}
54
+
55
+ subject { rewriter.rewrite(ast).to_s }
56
+
57
+ it { should == '(+ (+ "hello ", who), (* "!", 3))' }
58
+ end
59
+
60
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # semantics section" do
4
+
5
+ [
6
+ [ lambda { 12 }, "(_ 12)" ],
7
+ [ lambda { :x }, "(_ :x)" ],
8
+ [ lambda { x }, "(? (_ :x))" ]
9
+ ].each do |expr, expected|
10
+ specify { CodeTree::parse(expr).inspect.should == expected }
11
+ end
12
+
13
+ [
14
+ [ lambda { x + 12 }, :inspect, "(+ (? (_ :x)), (_ 12))" ],
15
+ [ lambda { x + 12 }, :to_s, "(+ x, 12)" ],
16
+ ].each do |expr, meth, expected|
17
+ specify { CodeTree::parse(expr).send(meth).should == expected }
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # synopsis section" do
4
+
5
+ let(:expr){ CodeTree::expr{ x > y } }
6
+
7
+ specify {
8
+ expr.to_s.should == "(> x, y)"
9
+ }
10
+
11
+ specify {
12
+ expr.inspect.should == "(> (? (_ :x)), (? (_ :y)))"
13
+ }
14
+
15
+ specify {
16
+ expr.eval(:x => 5, :y => 2).should == true
17
+ }
18
+
19
+ describe "what is said about marshalling" do
20
+ let(:marshaled) { Marshal::dump(expr) }
21
+ let(:unmarshaled) { Marshal::load(marshaled) }
22
+ subject { unmarshaled }
23
+ it { should == expr }
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,26 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "README # syntax section" do
4
+
5
+ describe "what is said about imperative styles" do
6
+ let(:expected) { "(& (> x, 5), (<= z, 10))" }
7
+
8
+ let(:hash_style) { lambda{|t| (t[:x] > 5) & (t[:z] <= 10) } }
9
+ let(:object_style) { lambda{|t| (t.x > 5) & (t.z <= 10) } }
10
+ let(:context_style) { lambda{ (x > 5) & (z <= 10) } }
11
+ let(:tested) { [hash_style, object_style, context_style] }
12
+
13
+ subject{ tested.collect{|t| CodeTree::parse(t) } }
14
+
15
+ specify{ subject.collect{|c| c.to_s}.uniq.should == [ expected ] }
16
+ end
17
+
18
+ describe "what is said about functional style" do
19
+ let(:functional) { lambda{ (both (gt x, 5), (lte y, 10)) } }
20
+
21
+ subject { CodeTree::parse(functional) }
22
+
23
+ specify{ subject.to_s.should == "(both (gt x, 5), (lte y, 10))" }
24
+ end
25
+
26
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../', __FILE__))
2
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'sbyc'
6
+ require 'spec'
7
+ require 'spec/autorun'
8
+
9
+ # require spec support files
10
+ Dir[File.expand_path('../support/**/*.spec', __FILE__)].each { |f| require f }
11
+
12
+ Spec::Runner.configure do |config|
13
+ end
@@ -0,0 +1,6 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ test_files = Dir[File.join(File.dirname(__FILE__), '**/*.spec')]
3
+ test_files.each { |file|
4
+ ::Kernel.load(file)
5
+ }
6
+
@@ -0,0 +1,60 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#coerce" do
4
+
5
+ context("with a literal") do
6
+ subject { CodeTree::AstNode.coerce(12) }
7
+
8
+ it { should be_kind_of(CodeTree::AstNode) }
9
+
10
+ specify {
11
+ subject.literal.should == 12
12
+ subject.children.should == [ 12 ]
13
+ subject.to_s.should == "12"
14
+ subject.inspect.should == "(_ 12)"
15
+ }
16
+ end
17
+
18
+ context("with a literal in array form") do
19
+ subject { CodeTree::AstNode.coerce([:_, [ 12 ]]) }
20
+ it { should be_kind_of(CodeTree::AstNode) }
21
+ specify { subject.inspect.should == "(_ 12)" }
22
+ end
23
+
24
+ context("without children") do
25
+ subject { CodeTree::AstNode.coerce([:plus, []]) }
26
+
27
+ it { should be_kind_of(CodeTree::AstNode) }
28
+
29
+ specify {
30
+ subject.name.should == :plus
31
+ subject.children.should be_empty
32
+ }
33
+ end
34
+
35
+ context("with literal children") do
36
+ subject { CodeTree::AstNode.coerce([ :plus, [ 12, 15 ] ]) }
37
+
38
+ it { should be_kind_of(CodeTree::AstNode) }
39
+
40
+ specify {
41
+ subject.name.should == :plus
42
+ subject.children.collect{|a| a.literal}.should == [ 12, 15 ]
43
+ }
44
+ end
45
+
46
+ context("with complex structure") do
47
+ subject { CodeTree::AstNode.coerce([ :plus, [ [ :minus, [12, 15] ] ] ]) }
48
+
49
+ it { should be_kind_of(CodeTree::AstNode) }
50
+
51
+ specify {
52
+ subject.name.should == :plus
53
+ subject.children.size.should == 1
54
+ subject.children[0].name.should == :minus
55
+ subject.children[0].children.should be_kind_of(Array)
56
+ subject.children[0].children.collect{|a| a.literal}.should == [12, 15]
57
+ }
58
+ end
59
+
60
+ end
@@ -0,0 +1,75 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#==" do
4
+
5
+ context "when applied on equal literal nodes" do
6
+ let(:n1) { CodeTree::parse{ 12 } }
7
+ let(:n2) { CodeTree::parse{ 12 } }
8
+ subject { (n1 == n2) and (n2 == n1) }
9
+ it { should be_true }
10
+ end
11
+
12
+ context "when applied on itself with a literal node" do
13
+ let(:n1) { CodeTree::parse{ 12 } }
14
+ let(:n2) { n1 }
15
+ subject { (n1 == n2) and (n2 == n1) }
16
+ it { should be_true }
17
+ end
18
+
19
+ context "when applied on non equal literal nodes" do
20
+ let(:n1) { CodeTree::parse{ 12 } }
21
+ let(:n2) { CodeTree::parse{ 13 } }
22
+ subject { (n1 == n2) or (n2 == n1) }
23
+ it { should be_false }
24
+ end
25
+
26
+ context "when applied on itself with a tree" do
27
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
28
+ let(:n2) { n1 }
29
+ subject { (n1 == n2) and (n2 == n1) }
30
+ it { should be_true }
31
+ end
32
+
33
+ context "when applied on equal trees" do
34
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
35
+ let(:n2) { CodeTree::parse{ (concat (say "hello"), "world") } }
36
+ subject { (n1 == n2) and (n2 == n1) }
37
+ it { should be_true }
38
+ end
39
+
40
+ context "when applied on non equal trees (with one being a literal)" do
41
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
42
+ let(:n2) { 12 }
43
+ subject { (n1 == n2) or (n2 == n1) }
44
+ it { should be_false }
45
+ end
46
+
47
+ context "when applied on non equal trees (none being a literal)" do
48
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
49
+ let(:n2) { CodeTree::parse{ (concat "hello", "world") } }
50
+ subject { (n1 == n2) or (n2 == n1) }
51
+ it { should be_false }
52
+ end
53
+
54
+ context "when applied on non equal trees (with a literal difference)" do
55
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
56
+ let(:n2) { CodeTree::parse{ (concat (say "hello"), "world2") } }
57
+ subject { (n1 == n2) or (n2 == n1) }
58
+ it { should be_false }
59
+ end
60
+
61
+ context "when applied on non equal trees (with a function difference)" do
62
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
63
+ let(:n2) { CodeTree::parse{ (concat (say2 "hello"), "world") } }
64
+ subject { (n1 == n2) or (n2 == n1) }
65
+ it { should be_false }
66
+ end
67
+
68
+ context "when applied on non equal trees (order difference)" do
69
+ let(:n1) { CodeTree::parse{ (concat (say "hello"), "world") } }
70
+ let(:n2) { CodeTree::parse{ (concat "world", (say "hello")) } }
71
+ subject { (n1 == n2) or (n2 == n1) }
72
+ it { should be_false }
73
+ end
74
+
75
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#inspect" do
4
+
5
+ subject{ node.inspect }
6
+
7
+ context('when called on a leaf node, through coercion') do
8
+ let(:node) { CodeTree::AstNode.coerce(12) }
9
+ it { should == "(_ 12)" }
10
+ end
11
+
12
+ context('when called on a ?') do
13
+ let(:node) { CodeTree::AstNode.coerce([:'?', [:x]]) }
14
+ it { should == "(? (_ :x))" }
15
+ end
16
+
17
+ context('when called on a object-like expression') do
18
+ let(:node) { CodeTree::parse{ (say x, "Hello") } }
19
+ it { subject.should == '(say (? (_ :x)), (_ "Hello"))' }
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#literal" do
4
+
5
+ context "when called on a leaf node" do
6
+ subject{ CodeTree::parse{ 12 }.literal }
7
+ it { should == 12 }
8
+ end
9
+
10
+ context "when called on a branch node" do
11
+ subject{ CodeTree::parse{ ~(~(12)) }.literal }
12
+ it { should == 12 }
13
+ end
14
+
15
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#to_a" do
4
+
5
+ context("with a _") do
6
+ subject { CodeTree::AstNode.coerce(12).to_a }
7
+ it { should == [:_, [ 12 ]] }
8
+ end
9
+
10
+ context("without children") do
11
+ subject { CodeTree::AstNode.coerce([ :plus, [ ] ]).to_a }
12
+ it { should == [ :plus, [ ] ] }
13
+ end
14
+
15
+ context("with _ children") do
16
+ let(:expected) { [ :plus, [ [:_, [12]], [:_, [15]] ] ] }
17
+ subject { CodeTree::parse{ (plus 12, 15) }.to_a }
18
+ it { should == expected }
19
+ end
20
+
21
+ context("with variables") do
22
+ let(:expected) { [ :plus, [ [:'?', [ [:_, [ :x ] ] ] ] ] ] }
23
+ subject { CodeTree::parse{ (plus x) }.to_a }
24
+ it { should == expected }
25
+ end
26
+
27
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../../../../../spec_helper', __FILE__)
2
+
3
+ describe "CodeTree::AstNode#inspect" do
4
+
5
+ subject{ node.to_s }
6
+
7
+ context('when called on a leaf node, through coercion') do
8
+ let(:node) { CodeTree::AstNode.coerce(12) }
9
+ it { should == "12" }
10
+ end
11
+
12
+ context('when called on a ?') do
13
+ let(:node) { CodeTree::AstNode.coerce([:'?', [:x]]) }
14
+ it { should == "x" }
15
+ end
16
+
17
+ context('when called on a object-like expression') do
18
+ let(:node) { CodeTree::parse{ (say x, "Hello") } }
19
+ it { subject.should == '(say x, "Hello")' }
20
+ end
21
+
22
+ end
23
+
@@ -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, through coercion') do
6
+ let(:node) { CodeTree::AstNode.coerce(12) }
7
+ subject{ node.visit{|node, collected| [node, collected]} }
8
+ it { should == [node, [12]] }
9
+ end
10
+
11
+ context('when called on a object-like expression') do
12
+ let(:node) { CodeTree::parse{ (say x, "Hello") } }
13
+ subject{ node.visit{|node, collected| [node.name, collected]} }
14
+ it { subject.should == [:say, [ [ :'?', [ [ :_, [ :x ] ] ] ], [ :_, [ "Hello" ] ] ] ] }
15
+ end
16
+
17
+ context('when called for productions') do
18
+ let(:node) { CodeTree::parse{ (say x, "Hello") } }
19
+ subject {
20
+ node.produce{|n, collected|
21
+ case n.function
22
+ when :'_'
23
+ collected.first.inspect
24
+ when :'?'
25
+ "scope[#{collected.join(', ')}]"
26
+ else
27
+ "#{collected.shift}.#{n.function}(#{collected.join(', ')})"
28
+ end
29
+ }
30
+ }
31
+ it { should == 'scope[:x].say("Hello")' }
32
+ end
33
+
34
+ end