qrb 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +30 -1
- data/lib/qrb.rb +6 -0
- data/lib/qrb/data_type.rb +7 -1
- data/lib/qrb/support/dress_helper.rb +1 -1
- data/lib/qrb/support/type_factory.rb +6 -0
- data/lib/qrb/syntax.rb +7 -0
- data/lib/qrb/syntax/ad_type.rb +7 -0
- data/lib/qrb/syntax/any_type.rb +16 -0
- data/lib/qrb/syntax/attribute.rb +4 -0
- data/lib/qrb/syntax/builtin_type.rb +4 -0
- data/lib/qrb/syntax/constraint_def.rb +6 -0
- data/lib/qrb/syntax/constraints.rb +4 -0
- data/lib/qrb/syntax/contract.rb +21 -9
- data/lib/qrb/syntax/definitions.rb +4 -0
- data/lib/qrb/syntax/external_pair.rb +17 -0
- data/lib/qrb/syntax/heading.rb +4 -0
- data/lib/qrb/syntax/inline_pair.rb +16 -0
- data/lib/qrb/syntax/lambda_expr.rb +4 -0
- data/lib/qrb/syntax/named_constraint.rb +6 -0
- data/lib/qrb/syntax/q.citrus +29 -4
- data/lib/qrb/syntax/q.sexp +114 -0
- data/lib/qrb/syntax/relation_type.rb +4 -0
- data/lib/qrb/syntax/seq_type.rb +4 -0
- data/lib/qrb/syntax/set_type.rb +4 -0
- data/lib/qrb/syntax/sub_type.rb +4 -0
- data/lib/qrb/syntax/system.rb +6 -0
- data/lib/qrb/syntax/tuple_type.rb +4 -0
- data/lib/qrb/syntax/type_def.rb +4 -0
- data/lib/qrb/syntax/type_ref.rb +4 -0
- data/lib/qrb/syntax/union_type.rb +4 -0
- data/lib/qrb/syntax/unnamed_constraint.rb +6 -0
- data/lib/qrb/type.rb +1 -0
- data/lib/qrb/type/ad_type.rb +8 -7
- data/lib/qrb/type/any_type.rb +47 -0
- data/lib/qrb/version.rb +1 -1
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/qrb/test_ast.rb +43 -0
- data/spec/unit/syntax/nodes/test_ad_type.rb +72 -0
- data/spec/unit/syntax/nodes/test_any_type.rb +30 -0
- data/spec/unit/syntax/nodes/test_attribute.rb +23 -10
- data/spec/unit/syntax/nodes/test_builtin_type.rb +25 -13
- data/spec/unit/syntax/nodes/test_constraint_def.rb +14 -0
- data/spec/unit/syntax/nodes/test_constraints.rb +35 -0
- data/spec/unit/syntax/nodes/test_contract.rb +76 -4
- data/spec/unit/syntax/nodes/test_heading.rb +37 -20
- data/spec/unit/syntax/nodes/test_named_constraint.rb +12 -0
- data/spec/unit/syntax/nodes/test_relation_type.rb +38 -20
- data/spec/unit/syntax/nodes/test_seq_type.rb +23 -9
- data/spec/unit/syntax/nodes/test_set_type.rb +23 -9
- data/spec/unit/syntax/nodes/test_sub_type.rb +29 -0
- data/spec/unit/syntax/nodes/test_system.rb +48 -0
- data/spec/unit/syntax/nodes/test_tuple_type.rb +38 -20
- data/spec/unit/syntax/nodes/test_type_def.rb +33 -0
- data/spec/unit/syntax/nodes/test_type_ref.rb +37 -0
- data/spec/unit/syntax/nodes/test_union_type.rb +23 -8
- data/spec/unit/syntax/nodes/test_unnamed_constraint.rb +12 -0
- data/spec/unit/type/ad_type/test_default_name.rb +2 -2
- data/spec/unit/type/ad_type/test_dress.rb +3 -3
- data/spec/unit/type/ad_type/test_initialize.rb +2 -2
- data/spec/unit/type/any_type/test_default_name.rb +12 -0
- data/spec/unit/type/any_type/test_dress.rb +22 -0
- data/spec/unit/type/any_type/test_equality.rb +26 -0
- data/spec/unit/type/any_type/test_include.rb +22 -0
- data/spec/unit/type/any_type/test_initialize.rb +10 -0
- data/spec/unit/type/any_type/test_name.rb +24 -0
- data/spec/unit/type_factory/dsl/test_adt.rb +2 -2
- data/spec/unit/type_factory/dsl/test_any.rb +28 -0
- 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
|
-
|
10
|
-
|
11
|
-
|
9
|
+
describe 'compilation result' do
|
10
|
+
let(:compiled){
|
11
|
+
subject.compile(type_factory)
|
12
|
+
}
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
context 'a: .Integer' do
|
15
|
+
let(:input){ 'a: .Integer' }
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
10
|
-
|
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
|
-
|
14
|
-
|
23
|
+
context 'when a qualified class name' do
|
24
|
+
let(:source){ ".Qrb::Type" }
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
33
|
+
describe "AST" do
|
23
34
|
let(:source){ ".Qrb::Type" }
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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.
|
25
|
-
contract.
|
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.
|
41
|
-
contract.
|
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
|
-
|
10
|
-
|
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
|
-
|
14
|
-
|
23
|
+
context 'a: .Integer' do
|
24
|
+
let(:input){ 'a: .Integer' }
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
23
|
-
|
32
|
+
context 'a: .Integer, b: .Float' do
|
33
|
+
let(:input){ 'a: .Integer, b: .Float' }
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
42
|
+
describe "AST" do
|
32
43
|
let(:input){ 'a: .Integer, b: .Float' }
|
33
44
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
10
|
-
|
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
|
-
|
14
|
-
|
23
|
+
context '{{a: .Integer}}' do
|
24
|
+
let(:input){ '{{a: .Integer}}' }
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
23
|
-
|
32
|
+
context '{{a: .Integer, b: .Float}}' do
|
33
|
+
let(:input){ '{{a: .Integer, b: .Float}}' }
|
24
34
|
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
32
|
-
let(:input){ '{{a: .Integer
|
42
|
+
describe "AST" do
|
43
|
+
let(:input){ '{{a: .Integer}}' }
|
33
44
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|