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.
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,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]+$/
@@ -6,6 +6,10 @@ module Qrb
6
6
  factory.relation(heading.compile(factory))
7
7
  end
8
8
 
9
+ def to_ast
10
+ [:relation_type, heading.to_ast]
11
+ end
12
+
9
13
  end # module RelationType
10
14
  end # module Syntax
11
15
  end # module Qrb
@@ -7,6 +7,10 @@ module Qrb
7
7
  factory.seq(elm_type)
8
8
  end
9
9
 
10
+ def to_ast
11
+ [:seq_type, type.to_ast]
12
+ end
13
+
10
14
  end # module SeqType
11
15
  end # module Syntax
12
16
  end # module Qrb
@@ -7,6 +7,10 @@ module Qrb
7
7
  factory.set(elm_type)
8
8
  end
9
9
 
10
+ def to_ast
11
+ [:set_type, type.to_ast]
12
+ end
13
+
10
14
  end # module SetType
11
15
  end # module Syntax
12
16
  end # module Qrb
@@ -8,6 +8,10 @@ module Qrb
8
8
  factory.subtype(s, c)
9
9
  end
10
10
 
11
+ def to_ast
12
+ [:sub_type, rel_type.to_ast] + constraint_def.to_ast
13
+ end
14
+
11
15
  end # module SubType
12
16
  end # module Syntax
13
17
  end # module Qrb
@@ -10,6 +10,12 @@ module Qrb
10
10
  system
11
11
  end
12
12
 
13
+ def to_ast
14
+ ast = [ :system ] + definitions.to_ast
15
+ ast << type.to_ast if type
16
+ ast
17
+ end
18
+
13
19
  end # module System
14
20
  end # module Syntax
15
21
  end # module Qrb
@@ -6,6 +6,10 @@ module Qrb
6
6
  factory.tuple(heading.compile(factory))
7
7
  end
8
8
 
9
+ def to_ast
10
+ [:tuple_type, heading.to_ast]
11
+ end
12
+
9
13
  end # module TupleType
10
14
  end # module Syntax
11
15
  end # module Qrb
@@ -9,6 +9,10 @@ module Qrb
9
9
  t
10
10
  end
11
11
 
12
+ def to_ast
13
+ [:type_def, type_name.to_s, type.to_ast]
14
+ end
15
+
12
16
  end # module TypeDef
13
17
  end # module Syntax
14
18
  end # module Qrb
@@ -8,6 +8,10 @@ module Qrb
8
8
  end
9
9
  end
10
10
 
11
+ def to_ast
12
+ [:type_ref, type_name.to_s]
13
+ end
14
+
11
15
  end # module TypeRef
12
16
  end # module Syntax
13
17
  end # module Qrb
@@ -7,6 +7,10 @@ module Qrb
7
7
  factory.union(cds)
8
8
  end
9
9
 
10
+ def to_ast
11
+ captures[:sub_type].map(&:to_ast).unshift(:union_type)
12
+ end
13
+
10
14
  end # module UnionType
11
15
  end # module Syntax
12
16
  end # module Qrb
@@ -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
@@ -53,6 +53,7 @@ module Qrb
53
53
 
54
54
  end # class Type
55
55
  end # module Qrb
56
+ require_relative 'type/any_type'
56
57
  require_relative 'type/builtin_type'
57
58
  require_relative 'type/union_type'
58
59
  require_relative 'type/sub_type'
@@ -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 == 2 and v.first.is_a?(Type) and v.last.respond_to?(:call)
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 uped.
90
- contracts.each_pair do |name, (infotype,upper)|
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, uped = handler.just_try do
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, uped = handler.just_try(StandardError) do
100
- upper.call(uped)
100
+ success, dressed = handler.just_try(StandardError) do
101
+ dresser.call(dressed)
101
102
  end
102
- return uped if success
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
@@ -2,7 +2,7 @@ module Qrb
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 2
5
+ MINOR = 3
6
6
  TINY = 0
7
7
 
8
8
  def self.to_s
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