qrb 0.2.0 → 0.3.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.
- 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
|