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,114 @@
|
|
1
|
+
### system
|
2
|
+
|
3
|
+
system:
|
4
|
+
- [ type_def* type ]
|
5
|
+
|
6
|
+
type_def:
|
7
|
+
- [ type_name type ]
|
8
|
+
|
9
|
+
### types
|
10
|
+
|
11
|
+
type:
|
12
|
+
- any_type
|
13
|
+
- builtin_type
|
14
|
+
- sub_type
|
15
|
+
- union_type
|
16
|
+
- set_type
|
17
|
+
- seq_type
|
18
|
+
- tuple_type
|
19
|
+
- relation_type
|
20
|
+
- ad_type
|
21
|
+
- type_ref
|
22
|
+
|
23
|
+
any_type:
|
24
|
+
- [ ]
|
25
|
+
|
26
|
+
builtin_type:
|
27
|
+
- [ ruby_module_name ]
|
28
|
+
|
29
|
+
sub_type:
|
30
|
+
- [ type, constraint+ ]
|
31
|
+
|
32
|
+
union_type:
|
33
|
+
- [ type+ ]
|
34
|
+
|
35
|
+
set_type:
|
36
|
+
- [ type ]
|
37
|
+
|
38
|
+
seq_type:
|
39
|
+
- [ type ]
|
40
|
+
|
41
|
+
tuple_type:
|
42
|
+
- [ heading ]
|
43
|
+
|
44
|
+
relation_type:
|
45
|
+
- [ heading ]
|
46
|
+
|
47
|
+
ad_type:
|
48
|
+
- [ ruby_module_name_or_nil, contract+ ]
|
49
|
+
|
50
|
+
type_ref:
|
51
|
+
- [ type_name ]
|
52
|
+
|
53
|
+
### heading
|
54
|
+
|
55
|
+
heading:
|
56
|
+
[ attribute+ ]
|
57
|
+
|
58
|
+
attribute:
|
59
|
+
[ attribute_name, type ]
|
60
|
+
|
61
|
+
### constraints
|
62
|
+
|
63
|
+
constraint:
|
64
|
+
- [ constraint_name, fn ]
|
65
|
+
|
66
|
+
### contracts
|
67
|
+
|
68
|
+
contract:
|
69
|
+
- [ contract_name, type, pair? ]
|
70
|
+
|
71
|
+
pair:
|
72
|
+
- external_pair
|
73
|
+
- inline_pair
|
74
|
+
|
75
|
+
inline_pair:
|
76
|
+
- [ fn, fn ]
|
77
|
+
|
78
|
+
external_pair:
|
79
|
+
- [ ruby_module_name ]
|
80
|
+
|
81
|
+
### functions/expressions
|
82
|
+
|
83
|
+
fn:
|
84
|
+
- [ parameters, source ]
|
85
|
+
|
86
|
+
parameters:
|
87
|
+
- [ parameter_name+ ]
|
88
|
+
|
89
|
+
source:
|
90
|
+
- [ String ]
|
91
|
+
|
92
|
+
### names
|
93
|
+
|
94
|
+
attribute_name:
|
95
|
+
!ruby/regexp /^[a-z][a-zA-Z0-9_]*$/
|
96
|
+
|
97
|
+
ruby_module_name:
|
98
|
+
!ruby/regexp /^[a-zA-Z0-9:]+$/
|
99
|
+
|
100
|
+
ruby_module_name_or_nil:
|
101
|
+
- ruby_module_name
|
102
|
+
- ~
|
103
|
+
|
104
|
+
contract_name:
|
105
|
+
!ruby/regexp /^[a-z][a-z0-9]*$/
|
106
|
+
|
107
|
+
constraint_name:
|
108
|
+
!ruby/regexp /^[a-z][a-zA-Z_]*$/
|
109
|
+
|
110
|
+
parameter_name:
|
111
|
+
!ruby/regexp /^[a-z]+$/
|
112
|
+
|
113
|
+
type_name:
|
114
|
+
!ruby/regexp /^[A-Z][a-zA-Z]+$/
|
data/lib/qrb/syntax/seq_type.rb
CHANGED
data/lib/qrb/syntax/set_type.rb
CHANGED
data/lib/qrb/syntax/sub_type.rb
CHANGED
data/lib/qrb/syntax/system.rb
CHANGED
data/lib/qrb/syntax/type_def.rb
CHANGED
data/lib/qrb/syntax/type_ref.rb
CHANGED
@@ -6,6 +6,12 @@ module Qrb
|
|
6
6
|
{ predicate: expression.compile(var_name) }
|
7
7
|
end
|
8
8
|
|
9
|
+
def to_ast(var_name)
|
10
|
+
[ :constraint,
|
11
|
+
"default",
|
12
|
+
[:fn, [:parameters, var_name], [:source, expression.to_s.strip]] ]
|
13
|
+
end
|
14
|
+
|
9
15
|
end # module UnnamedConstraint
|
10
16
|
end # module Syntax
|
11
17
|
end # module Qrb
|
data/lib/qrb/type.rb
CHANGED
data/lib/qrb/type/ad_type.rb
CHANGED
@@ -56,7 +56,8 @@ module Qrb
|
|
56
56
|
raise ArgumentError, "Hash expected, got `#{contracts}`"
|
57
57
|
end
|
58
58
|
invalid = contracts.values.reject{|v|
|
59
|
-
v.is_a?(Array) and v.size ==
|
59
|
+
v.is_a?(Array) and v.size == 3 and v[0].is_a?(Type) and \
|
60
|
+
v[1].respond_to?(:call) and v[2].respond_to?(:call)
|
60
61
|
}
|
61
62
|
unless invalid.empty?
|
62
63
|
raise ArgumentError, "Invalid contracts `#{invalid}`"
|
@@ -86,20 +87,20 @@ module Qrb
|
|
86
87
|
|
87
88
|
# Try each contract in turn. Do nothing on TypeError as
|
88
89
|
# the next candidate could be the good one! Return the
|
89
|
-
# first successfully
|
90
|
-
contracts.each_pair do |name, (infotype,
|
90
|
+
# first successfully dressed.
|
91
|
+
contracts.each_pair do |name, (infotype, dresser, _)|
|
91
92
|
|
92
93
|
# First make the dress transformation on the information type
|
93
|
-
success,
|
94
|
+
success, dressed = handler.just_try do
|
94
95
|
infotype.dress(value, handler)
|
95
96
|
end
|
96
97
|
next unless success
|
97
98
|
|
98
99
|
# Seems nice, just try to get one stage higher now
|
99
|
-
success,
|
100
|
-
|
100
|
+
success, dressed = handler.just_try(StandardError) do
|
101
|
+
dresser.call(dressed)
|
101
102
|
end
|
102
|
-
return
|
103
|
+
return dressed if success
|
103
104
|
|
104
105
|
end
|
105
106
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Qrb
|
2
|
+
#
|
3
|
+
# An AnyType generator allows capuring the set of every ruby citizen as a Q
|
4
|
+
# type.
|
5
|
+
#
|
6
|
+
# Any := .
|
7
|
+
#
|
8
|
+
# Object is used as concrete representation of the information type as the
|
9
|
+
# Ruby `Object` class already captures everything.
|
10
|
+
#
|
11
|
+
# R(.) = Object
|
12
|
+
#
|
13
|
+
# Accordingly, the `dress` transformation function has the signature below.
|
14
|
+
# Note that dress always succeeds and returns its first argument.
|
15
|
+
#
|
16
|
+
# dress :: Alpha -> Object throws TypeError
|
17
|
+
# dress :: Object -> Object throws TypeError
|
18
|
+
#
|
19
|
+
class AnyType < Type
|
20
|
+
|
21
|
+
def initialize(name = nil)
|
22
|
+
super(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_name
|
26
|
+
"Any"
|
27
|
+
end
|
28
|
+
|
29
|
+
def include?(value)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def dress(value, handler = nil)
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
other.is_a?(AnyType)
|
39
|
+
end
|
40
|
+
alias :eql? :==
|
41
|
+
|
42
|
+
def hash
|
43
|
+
self.class.hash ^ 37
|
44
|
+
end
|
45
|
+
|
46
|
+
end # class AnyType
|
47
|
+
end # module Qrb
|
data/lib/qrb/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -35,6 +35,13 @@ class Color
|
|
35
35
|
|
36
36
|
end
|
37
37
|
|
38
|
+
module ExternalContract
|
39
|
+
def self.dress(x)
|
40
|
+
end
|
41
|
+
def self.undress(y)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
38
45
|
module SpecHelpers
|
39
46
|
|
40
47
|
def intType
|
@@ -57,6 +64,10 @@ module SpecHelpers
|
|
57
64
|
Qrb::TypeFactory.new
|
58
65
|
end
|
59
66
|
|
67
|
+
def system
|
68
|
+
Qrb::System.new
|
69
|
+
end
|
70
|
+
|
60
71
|
def blueviolet
|
61
72
|
Color.new(138, 43, 226)
|
62
73
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Qrb, "ast" do
|
3
|
+
|
4
|
+
subject{
|
5
|
+
Qrb.ast <<-EOF
|
6
|
+
Posint = .Fixnum( i | i>=0 )
|
7
|
+
Point = { x: Posint, y: Posint }
|
8
|
+
{{ p: Point }}
|
9
|
+
EOF
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:expected){
|
13
|
+
[ :system,
|
14
|
+
[ :type_def,
|
15
|
+
"Posint",
|
16
|
+
[ :sub_type,
|
17
|
+
[:builtin_type, "Fixnum"],
|
18
|
+
[ :constraint,
|
19
|
+
"default",
|
20
|
+
[:fn, [:parameters, "i"], [:source, "i>=0"] ]
|
21
|
+
]
|
22
|
+
]
|
23
|
+
],
|
24
|
+
[ :type_def,
|
25
|
+
"Point",
|
26
|
+
[ :tuple_type,
|
27
|
+
[ :heading,
|
28
|
+
[:attribute, "x", [:type_ref, "Posint"]],
|
29
|
+
[:attribute, "y", [:type_ref, "Posint"]]
|
30
|
+
]
|
31
|
+
]
|
32
|
+
],
|
33
|
+
[ :relation_type,
|
34
|
+
[ :heading,
|
35
|
+
[:attribute, "p", [:type_ref, "Point"]]
|
36
|
+
]
|
37
|
+
]
|
38
|
+
]
|
39
|
+
}
|
40
|
+
|
41
|
+
it{ should eq(expected) }
|
42
|
+
|
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 'One contract' do
|
14
18
|
let(:input){ '.Color <rgb> {r: .Integer, g: .Integer, b: .Integer}' }
|
15
19
|
|
@@ -22,6 +26,23 @@ module Qrb
|
|
22
26
|
it 'should behave as expected' do
|
23
27
|
compiled.dress(r: 138, g: 43, b: 226).should eq(blueviolet)
|
24
28
|
end
|
29
|
+
|
30
|
+
it 'has expected AST' do
|
31
|
+
ast.should eq([
|
32
|
+
:ad_type,
|
33
|
+
"Color",
|
34
|
+
[:contract,
|
35
|
+
"rgb",
|
36
|
+
[:tuple_type,
|
37
|
+
[:heading,
|
38
|
+
[:attribute, "r", [:builtin_type, "Integer"]],
|
39
|
+
[:attribute, "g", [:builtin_type, "Integer"]],
|
40
|
+
[:attribute, "b", [:builtin_type, "Integer"]]
|
41
|
+
]
|
42
|
+
]
|
43
|
+
]
|
44
|
+
])
|
45
|
+
end
|
25
46
|
end
|
26
47
|
|
27
48
|
context 'Two contracts' do
|
@@ -41,6 +62,27 @@ module Qrb
|
|
41
62
|
it 'should behave as expected' do
|
42
63
|
compiled.dress("#8A2BE2").should eq(blueviolet)
|
43
64
|
end
|
65
|
+
|
66
|
+
it 'has expected AST' do
|
67
|
+
ast.should eq([
|
68
|
+
:ad_type,
|
69
|
+
"Color",
|
70
|
+
[:contract,
|
71
|
+
"rgb",
|
72
|
+
[:tuple_type,
|
73
|
+
[:heading,
|
74
|
+
[:attribute, "r", [:builtin_type, "Integer"]],
|
75
|
+
[:attribute, "g", [:builtin_type, "Integer"]],
|
76
|
+
[:attribute, "b", [:builtin_type, "Integer"]]
|
77
|
+
]
|
78
|
+
]
|
79
|
+
],
|
80
|
+
[:contract,
|
81
|
+
"hex",
|
82
|
+
[:builtin_type, "String"]
|
83
|
+
]
|
84
|
+
])
|
85
|
+
end
|
44
86
|
end
|
45
87
|
|
46
88
|
context 'No ruby class' do
|
@@ -58,6 +100,21 @@ module Qrb
|
|
58
100
|
compiled.dress("foo")
|
59
101
|
}.should raise_error(TypeError)
|
60
102
|
end
|
103
|
+
|
104
|
+
it 'has expected AST' do
|
105
|
+
ast.should eq([
|
106
|
+
:ad_type,
|
107
|
+
nil,
|
108
|
+
[:contract,
|
109
|
+
"as",
|
110
|
+
[:tuple_type,
|
111
|
+
[:heading,
|
112
|
+
[:attribute, "r", [:builtin_type, "Integer"]],
|
113
|
+
]
|
114
|
+
]
|
115
|
+
]
|
116
|
+
])
|
117
|
+
end
|
61
118
|
end
|
62
119
|
|
63
120
|
context 'Duplicate contract name' do
|
@@ -88,6 +145,21 @@ module Qrb
|
|
88
145
|
err.should be_a(TypeError)
|
89
146
|
err.message.should eq("Invalid value `foo` for DateTime")
|
90
147
|
end
|
148
|
+
|
149
|
+
it 'has expected AST' do
|
150
|
+
ast.should eq([
|
151
|
+
:ad_type,
|
152
|
+
"DateTime",
|
153
|
+
[:contract,
|
154
|
+
"iso",
|
155
|
+
[:builtin_type, "String"],
|
156
|
+
[:inline_pair,
|
157
|
+
[:fn, [:parameters, "s"], [:source, "DateTime.parse(s)"]],
|
158
|
+
[:fn, [:parameters, "d"], [:source, "d.to_s"]],
|
159
|
+
]
|
160
|
+
]
|
161
|
+
])
|
162
|
+
end
|
91
163
|
end
|
92
164
|
|
93
165
|
end
|