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