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