qrb 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/CHANGELOG.md +7 -0
  2. data/Gemfile.lock +1 -1
  3. data/README.md +30 -1
  4. data/lib/qrb.rb +6 -0
  5. data/lib/qrb/data_type.rb +7 -1
  6. data/lib/qrb/support/dress_helper.rb +1 -1
  7. data/lib/qrb/support/type_factory.rb +6 -0
  8. data/lib/qrb/syntax.rb +7 -0
  9. data/lib/qrb/syntax/ad_type.rb +7 -0
  10. data/lib/qrb/syntax/any_type.rb +16 -0
  11. data/lib/qrb/syntax/attribute.rb +4 -0
  12. data/lib/qrb/syntax/builtin_type.rb +4 -0
  13. data/lib/qrb/syntax/constraint_def.rb +6 -0
  14. data/lib/qrb/syntax/constraints.rb +4 -0
  15. data/lib/qrb/syntax/contract.rb +21 -9
  16. data/lib/qrb/syntax/definitions.rb +4 -0
  17. data/lib/qrb/syntax/external_pair.rb +17 -0
  18. data/lib/qrb/syntax/heading.rb +4 -0
  19. data/lib/qrb/syntax/inline_pair.rb +16 -0
  20. data/lib/qrb/syntax/lambda_expr.rb +4 -0
  21. data/lib/qrb/syntax/named_constraint.rb +6 -0
  22. data/lib/qrb/syntax/q.citrus +29 -4
  23. data/lib/qrb/syntax/q.sexp +114 -0
  24. data/lib/qrb/syntax/relation_type.rb +4 -0
  25. data/lib/qrb/syntax/seq_type.rb +4 -0
  26. data/lib/qrb/syntax/set_type.rb +4 -0
  27. data/lib/qrb/syntax/sub_type.rb +4 -0
  28. data/lib/qrb/syntax/system.rb +6 -0
  29. data/lib/qrb/syntax/tuple_type.rb +4 -0
  30. data/lib/qrb/syntax/type_def.rb +4 -0
  31. data/lib/qrb/syntax/type_ref.rb +4 -0
  32. data/lib/qrb/syntax/union_type.rb +4 -0
  33. data/lib/qrb/syntax/unnamed_constraint.rb +6 -0
  34. data/lib/qrb/type.rb +1 -0
  35. data/lib/qrb/type/ad_type.rb +8 -7
  36. data/lib/qrb/type/any_type.rb +47 -0
  37. data/lib/qrb/version.rb +1 -1
  38. data/spec/spec_helper.rb +11 -0
  39. data/spec/unit/qrb/test_ast.rb +43 -0
  40. data/spec/unit/syntax/nodes/test_ad_type.rb +72 -0
  41. data/spec/unit/syntax/nodes/test_any_type.rb +30 -0
  42. data/spec/unit/syntax/nodes/test_attribute.rb +23 -10
  43. data/spec/unit/syntax/nodes/test_builtin_type.rb +25 -13
  44. data/spec/unit/syntax/nodes/test_constraint_def.rb +14 -0
  45. data/spec/unit/syntax/nodes/test_constraints.rb +35 -0
  46. data/spec/unit/syntax/nodes/test_contract.rb +76 -4
  47. data/spec/unit/syntax/nodes/test_heading.rb +37 -20
  48. data/spec/unit/syntax/nodes/test_named_constraint.rb +12 -0
  49. data/spec/unit/syntax/nodes/test_relation_type.rb +38 -20
  50. data/spec/unit/syntax/nodes/test_seq_type.rb +23 -9
  51. data/spec/unit/syntax/nodes/test_set_type.rb +23 -9
  52. data/spec/unit/syntax/nodes/test_sub_type.rb +29 -0
  53. data/spec/unit/syntax/nodes/test_system.rb +48 -0
  54. data/spec/unit/syntax/nodes/test_tuple_type.rb +38 -20
  55. data/spec/unit/syntax/nodes/test_type_def.rb +33 -0
  56. data/spec/unit/syntax/nodes/test_type_ref.rb +37 -0
  57. data/spec/unit/syntax/nodes/test_union_type.rb +23 -8
  58. data/spec/unit/syntax/nodes/test_unnamed_constraint.rb +12 -0
  59. data/spec/unit/type/ad_type/test_default_name.rb +2 -2
  60. data/spec/unit/type/ad_type/test_dress.rb +3 -3
  61. data/spec/unit/type/ad_type/test_initialize.rb +2 -2
  62. data/spec/unit/type/any_type/test_default_name.rb +12 -0
  63. data/spec/unit/type/any_type/test_dress.rb +22 -0
  64. data/spec/unit/type/any_type/test_equality.rb +26 -0
  65. data/spec/unit/type/any_type/test_include.rb +22 -0
  66. data/spec/unit/type/any_type/test_initialize.rb +10 -0
  67. data/spec/unit/type/any_type/test_name.rb +24 -0
  68. data/spec/unit/type_factory/dsl/test_adt.rb +2 -2
  69. data/spec/unit/type_factory/dsl/test_any.rb +28 -0
  70. metadata +33 -4
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ module Qrb
3
+ describe Syntax, "any_type" do
4
+
5
+ subject{
6
+ Syntax.parse(source, root: "any_type")
7
+ }
8
+
9
+ let(:source){ "." }
10
+
11
+ describe "compilation result" do
12
+ let(:compiled){
13
+ subject.compile(type_factory)
14
+ }
15
+
16
+ it 'compiles to an AnyType' do
17
+ compiled.should be_a(AnyType)
18
+ end
19
+ end
20
+
21
+ describe "AST" do
22
+ let(:ast){
23
+ subject.to_ast
24
+ }
25
+
26
+ it{ ast.should eq([:any_type]) }
27
+ end
28
+
29
+ end
30
+ end
@@ -6,20 +6,33 @@ module Qrb
6
6
  Syntax.parse(input, root: "attribute")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe 'compilation result' do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
12
13
 
13
- context 'a: .Integer' do
14
- let(:input){ 'a: .Integer' }
14
+ context 'a: .Integer' do
15
+ let(:input){ 'a: .Integer' }
15
16
 
16
- it 'compiles to an Attribute' do
17
- compiled.should be_a(Attribute)
18
- compiled.name.should eq(:a)
19
- compiled.type.should be_a(BuiltinType)
20
- compiled.type.ruby_type.should be(Integer)
17
+ it 'compiles to an Attribute' do
18
+ compiled.should be_a(Attribute)
19
+ compiled.name.should eq(:a)
20
+ compiled.type.should be_a(BuiltinType)
21
+ compiled.type.ruby_type.should be(Integer)
22
+ end
21
23
  end
22
24
  end
23
25
 
26
+ describe 'AST' do
27
+ let(:ast){
28
+ subject.to_ast
29
+ }
30
+
31
+ let(:input){ 'a: .Integer' }
32
+
33
+ it{ ast.should eq([:attribute, "a", [:builtin_type, "Integer"]]) }
34
+ end
35
+
36
+
24
37
  end
25
38
  end
@@ -6,26 +6,38 @@ module Qrb
6
6
  Syntax.parse(source, root: "builtin_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
13
+
14
+ context 'when an unqualified class name' do
15
+ let(:source){ ".Integer" }
16
+
17
+ it 'compiles to a BuiltinType' do
18
+ compiled.should be_a(BuiltinType)
19
+ compiled.ruby_type.should be(Integer)
20
+ end
21
+ end
12
22
 
13
- context 'when an unqualified class name' do
14
- let(:source){ ".Integer" }
23
+ context 'when a qualified class name' do
24
+ let(:source){ ".Qrb::Type" }
15
25
 
16
- it 'compiles to a BuiltinType' do
17
- compiled.should be_a(BuiltinType)
18
- compiled.ruby_type.should be(Integer)
26
+ it 'compiles to a BuiltinType' do
27
+ compiled.should be_a(BuiltinType)
28
+ compiled.ruby_type.should be(::Qrb::Type)
29
+ end
19
30
  end
20
31
  end
21
32
 
22
- context 'when a qualified class name' do
33
+ describe "AST" do
23
34
  let(:source){ ".Qrb::Type" }
24
35
 
25
- it 'compiles to a BuiltinType' do
26
- compiled.should be_a(BuiltinType)
27
- compiled.ruby_type.should be(::Qrb::Type)
28
- end
36
+ let(:ast){
37
+ subject.to_ast
38
+ }
39
+
40
+ it{ ast.should eq([:builtin_type, "Qrb::Type"]) }
29
41
  end
30
42
 
31
43
  end
@@ -10,6 +10,10 @@ module Qrb
10
10
  subject.compile(type_factory)
11
11
  }
12
12
 
13
+ let(:ast){
14
+ subject.to_ast
15
+ }
16
+
13
17
  context '(i | i >= 0)' do
14
18
  let(:input){ '(i | i >= 0)' }
15
19
 
@@ -21,6 +25,16 @@ module Qrb
21
25
  compiled[:predicate].call(12).should be_true
22
26
  compiled[:predicate].call(-12).should be_false
23
27
  end
28
+
29
+ it 'has the expected AST' do
30
+ ast.should eq([
31
+ [
32
+ :constraint,
33
+ "default",
34
+ [:fn, [:parameters, "i"], [:source, "i >= 0"]]
35
+ ]
36
+ ])
37
+ end
24
38
  end
25
39
 
26
40
  end
@@ -10,6 +10,10 @@ module Qrb
10
10
  subject.compile("a")
11
11
  }
12
12
 
13
+ let(:ast){
14
+ subject.to_ast('a')
15
+ }
16
+
13
17
  context 'a >= 10' do
14
18
  let(:input){ 'a >= 10' }
15
19
 
@@ -17,6 +21,14 @@ module Qrb
17
21
  compiled.should be_a(Hash)
18
22
  compiled.keys.should eq([:predicate])
19
23
  end
24
+
25
+ it 'has the expected AST' do
26
+ ast.should eq([
27
+ :constraint,
28
+ "default",
29
+ [:fn, [:parameters, "a"], [:source, "a >= 10"]]
30
+ ])
31
+ end
20
32
  end
21
33
 
22
34
  context 'foo: a >= 10' do
@@ -26,6 +38,14 @@ module Qrb
26
38
  compiled.should be_a(Hash)
27
39
  compiled.keys.should eq([:foo])
28
40
  end
41
+
42
+ it 'has the expected AST' do
43
+ ast.should eq([[
44
+ :constraint,
45
+ "foo",
46
+ [:fn, [:parameters, "a"], [:source, "a >= 10"]]
47
+ ]])
48
+ end
29
49
  end
30
50
 
31
51
  context 'foo: a >= 10, bar: a <= 255' do
@@ -35,6 +55,21 @@ module Qrb
35
55
  compiled.should be_a(Hash)
36
56
  compiled.keys.should eq([:foo, :bar])
37
57
  end
58
+
59
+ it 'has the expected AST' do
60
+ ast.should eq([
61
+ [
62
+ :constraint,
63
+ "foo",
64
+ [:fn, [:parameters, "a"], [:source, "a >= 10"]]
65
+ ],
66
+ [
67
+ :constraint,
68
+ "bar",
69
+ [:fn, [:parameters, "a"], [:source, "a <= 255"]]
70
+ ]
71
+ ])
72
+ end
38
73
  end
39
74
 
40
75
  context 'foo: a >= 10, foo: a <= 255' do
@@ -10,6 +10,10 @@ module Qrb
10
10
  compiled.values.first
11
11
  }
12
12
 
13
+ let(:ast){
14
+ subject.to_ast
15
+ }
16
+
13
17
  context 'No converter and a class' do
14
18
  let(:input){ '<rgb> {r: .Integer, g: .Integer, b: .Integer}' }
15
19
 
@@ -21,8 +25,23 @@ module Qrb
21
25
  compiled.should be_a(Hash)
22
26
  compiled.keys.should eq([:rgb])
23
27
  contract.should be_a(Array)
24
- contract.first.should be_a(TupleType)
25
- contract.last.should be_a(Method)
28
+ contract[0].should be_a(TupleType)
29
+ contract[1].should be_a(Method)
30
+ contract[2].should be_a(Proc)
31
+ end
32
+
33
+ it 'has expected AST' do
34
+ ast.should eq([
35
+ :contract,
36
+ "rgb",
37
+ [:tuple_type,
38
+ [:heading,
39
+ [:attribute, "r", [:builtin_type, "Integer"]],
40
+ [:attribute, "g", [:builtin_type, "Integer"]],
41
+ [:attribute, "b", [:builtin_type, "Integer"]]
42
+ ]
43
+ ]
44
+ ])
26
45
  end
27
46
  end
28
47
 
@@ -37,8 +56,23 @@ module Qrb
37
56
  compiled.should be_a(Hash)
38
57
  compiled.keys.should eq([:rgb])
39
58
  contract.should be_a(Array)
40
- contract.first.should be_a(TupleType)
41
- contract.last.should be(Qrb::IDENTITY)
59
+ contract[0].should be_a(TupleType)
60
+ contract[1].should be(Qrb::IDENTITY)
61
+ contract[2].should be(Qrb::IDENTITY)
62
+ end
63
+
64
+ it 'has expected AST' do
65
+ ast.should eq([
66
+ :contract,
67
+ "rgb",
68
+ [:tuple_type,
69
+ [:heading,
70
+ [:attribute, "r", [:builtin_type, "Integer"]],
71
+ [:attribute, "g", [:builtin_type, "Integer"]],
72
+ [:attribute, "b", [:builtin_type, "Integer"]]
73
+ ]
74
+ ]
75
+ ])
42
76
  end
43
77
  end
44
78
 
@@ -56,6 +90,44 @@ module Qrb
56
90
  contract.first.should be_a(BuiltinType)
57
91
  contract.last.should be_a(Proc)
58
92
  end
93
+
94
+ it 'has expected AST' do
95
+ ast.should eq([
96
+ :contract,
97
+ "iso",
98
+ [:builtin_type, "String"],
99
+ [:inline_pair,
100
+ [:fn, [:parameters, "s"], [:source, "DateTime.parse(s)"]],
101
+ [:fn, [:parameters, "d"], [:source, "d.to_s"]]
102
+ ]
103
+ ])
104
+ end
105
+ end
106
+
107
+ context 'A contract with external dressers' do
108
+ let(:input){ '<iso> .String .ExternalContract' }
109
+
110
+ let(:compiled){
111
+ subject.compile(type_factory, nil)
112
+ }
113
+
114
+ it 'compiles to the expected Hash' do
115
+ compiled.should be_a(Hash)
116
+ compiled.keys.should eq([:iso])
117
+ contract.should be_a(Array)
118
+ contract[0].should be_a(BuiltinType)
119
+ contract[1].should be_a(Method)
120
+ contract[2].should be_a(Method)
121
+ end
122
+
123
+ it 'has expected AST' do
124
+ ast.should eq([
125
+ :contract,
126
+ "iso",
127
+ [:builtin_type, "String"],
128
+ [:external_pair, "ExternalContract"]
129
+ ])
130
+ end
59
131
  end
60
132
 
61
133
  end
@@ -6,36 +6,53 @@ module Qrb
6
6
  Syntax.parse(input, root: "heading")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
13
+
14
+ context 'empty heading' do
15
+ let(:input){ ' ' }
16
+
17
+ it 'compiles to a Heading' do
18
+ compiled.should be_a(Heading)
19
+ compiled.to_name.should eq('')
20
+ end
21
+ end
12
22
 
13
- context 'empty heading' do
14
- let(:input){ ' ' }
23
+ context 'a: .Integer' do
24
+ let(:input){ 'a: .Integer' }
15
25
 
16
- it 'compiles to a Heading' do
17
- compiled.should be_a(Heading)
18
- compiled.to_name.should eq('')
26
+ it 'compiles to a Heading' do
27
+ compiled.should be_a(Heading)
28
+ compiled.to_name.should eq('a: Integer')
29
+ end
19
30
  end
20
- end
21
31
 
22
- context 'a: .Integer' do
23
- let(:input){ 'a: .Integer' }
32
+ context 'a: .Integer, b: .Float' do
33
+ let(:input){ 'a: .Integer, b: .Float' }
24
34
 
25
- it 'compiles to a Heading' do
26
- compiled.should be_a(Heading)
27
- compiled.to_name.should eq('a: Integer')
35
+ it 'compiles to a Heading' do
36
+ compiled.should be_a(Heading)
37
+ compiled.to_name.should eq('a: Integer, b: Float')
38
+ end
28
39
  end
29
40
  end
30
41
 
31
- context 'a: .Integer, b: .Float' do
42
+ describe "AST" do
32
43
  let(:input){ 'a: .Integer, b: .Float' }
33
44
 
34
- it 'compiles to a Heading' do
35
- compiled.should be_a(Heading)
36
- compiled.to_name.should eq('a: Integer, b: Float')
37
- end
45
+ let(:ast){
46
+ subject.to_ast
47
+ }
48
+
49
+ it{
50
+ ast.should eq([
51
+ :heading,
52
+ [ :attribute, "a", [:builtin_type, "Integer" ]],
53
+ [ :attribute, "b", [:builtin_type, "Float" ]]
54
+ ])
55
+ }
38
56
  end
39
-
40
57
  end
41
58
  end
@@ -10,6 +10,10 @@ module Qrb
10
10
  subject.compile("a")
11
11
  }
12
12
 
13
+ let(:ast){
14
+ subject.to_ast('a')
15
+ }
16
+
13
17
  context 'a >= 10' do
14
18
  let(:input){ 'foo: a >= 10' }
15
19
 
@@ -25,6 +29,14 @@ module Qrb
25
29
  compiled[:foo].call(12).should be_true
26
30
  compiled[:foo].call(9).should be_false
27
31
  end
32
+
33
+ it 'has the expected AST' do
34
+ ast.should eq([
35
+ :constraint,
36
+ "foo",
37
+ [:fn, [:parameters, "a"], [:source, "a >= 10"]]
38
+ ])
39
+ end
28
40
  end
29
41
 
30
42
  end
@@ -6,35 +6,53 @@ module Qrb
6
6
  Syntax.parse(input, root: "relation_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
13
+
14
+ context 'empty heading' do
15
+ let(:input){ '{{ }}' }
16
+
17
+ it 'compiles to a RelationType' do
18
+ compiled.should be_a(RelationType)
19
+ compiled.heading.should be_empty
20
+ end
21
+ end
12
22
 
13
- context 'empty heading' do
14
- let(:input){ '{{ }}' }
23
+ context '{{a: .Integer}}' do
24
+ let(:input){ '{{a: .Integer}}' }
15
25
 
16
- it 'compiles to a RelationType' do
17
- compiled.should be_a(RelationType)
18
- compiled.heading.should be_empty
26
+ it 'compiles to a RelationType' do
27
+ compiled.should be_a(RelationType)
28
+ compiled.heading.size.should eq(1)
29
+ end
19
30
  end
20
- end
21
31
 
22
- context '{{a: .Integer}}' do
23
- let(:input){ '{{a: .Integer}}' }
32
+ context '{{a: .Integer, b: .Float}}' do
33
+ let(:input){ '{{a: .Integer, b: .Float}}' }
24
34
 
25
- it 'compiles to a RelationType' do
26
- compiled.should be_a(RelationType)
27
- compiled.heading.size.should eq(1)
35
+ it 'compiles to a RelationType' do
36
+ compiled.should be_a(RelationType)
37
+ compiled.heading.size.should eq(2)
38
+ end
28
39
  end
29
40
  end
30
41
 
31
- context '{{a: .Integer, b: .Float}}' do
32
- let(:input){ '{{a: .Integer, b: .Float}}' }
42
+ describe "AST" do
43
+ let(:input){ '{{a: .Integer}}' }
33
44
 
34
- it 'compiles to a RelationType' do
35
- compiled.should be_a(RelationType)
36
- compiled.heading.size.should eq(2)
37
- end
45
+ let(:ast){ subject.to_ast }
46
+
47
+ it{
48
+ ast.should eq([
49
+ :relation_type,
50
+ [
51
+ :heading,
52
+ [ :attribute, "a", [:builtin_type, "Integer" ]]
53
+ ]
54
+ ])
55
+ }
38
56
  end
39
57
 
40
58
  end