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
@@ -6,19 +6,33 @@ module Qrb
6
6
  Syntax.parse(input, root: "seq_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
12
13
 
13
- context '[.Integer]' do
14
- let(:input){ '[.Integer]' }
14
+ context '[.Integer]' do
15
+ let(:input){ '[.Integer]' }
15
16
 
16
- it 'compiles to a SeqType' do
17
- compiled.should be_a(SeqType)
18
- compiled.elm_type.should be_a(BuiltinType)
19
- compiled.elm_type.ruby_type.should be(Integer)
17
+ it 'compiles to a SeqType' do
18
+ compiled.should be_a(SeqType)
19
+ compiled.elm_type.should be_a(BuiltinType)
20
+ compiled.elm_type.ruby_type.should be(Integer)
21
+ end
20
22
  end
21
23
  end
22
24
 
25
+ describe "AST" do
26
+ let(:input){ '[.Integer]' }
27
+
28
+ let(:ast){ subject.to_ast }
29
+
30
+ it{ ast.should eq([
31
+ :seq_type,
32
+ [:builtin_type, "Integer"]
33
+ ])
34
+ }
35
+ end
36
+
23
37
  end
24
38
  end
@@ -6,19 +6,33 @@ module Qrb
6
6
  Syntax.parse(input, root: "set_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
12
13
 
13
- context '{.Integer}' do
14
- let(:input){ '{.Integer}' }
14
+ context '{.Integer}' do
15
+ let(:input){ '{.Integer}' }
15
16
 
16
- it 'compiles to a SeqType' do
17
- compiled.should be_a(SetType)
18
- compiled.elm_type.should be_a(BuiltinType)
19
- compiled.elm_type.ruby_type.should be(Integer)
17
+ it 'compiles to a SeqType' do
18
+ compiled.should be_a(SetType)
19
+ compiled.elm_type.should be_a(BuiltinType)
20
+ compiled.elm_type.ruby_type.should be(Integer)
21
+ end
20
22
  end
21
23
  end
22
24
 
25
+ describe "AST" do
26
+ let(:input){ '{.Integer}' }
27
+
28
+ let(:ast){ subject.to_ast }
29
+
30
+ it{ ast.should eq([
31
+ :set_type,
32
+ [:builtin_type, "Integer"]
33
+ ])
34
+ }
35
+ end
36
+
23
37
  end
24
38
  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 '.Integer( i | i >= 0 )' do
14
18
  let(:input){ '.Integer( i | i >= 0 )' }
15
19
 
@@ -18,6 +22,14 @@ module Qrb
18
22
  compiled.super_type.should be_a(BuiltinType)
19
23
  compiled.super_type.ruby_type.should be(Integer)
20
24
  end
25
+
26
+ it 'has the expected AST' do
27
+ ast.should eq([
28
+ :sub_type,
29
+ [:builtin_type, "Integer"],
30
+ [:constraint, "default", [:fn, [:parameters, "i"], [:source, "i >= 0"]]]
31
+ ])
32
+ end
21
33
  end
22
34
 
23
35
  context '.Integer( i | positive: i >= 0 )' do
@@ -32,6 +44,14 @@ module Qrb
32
44
  it 'has the correct constraints' do
33
45
  compiled.constraints.keys.should eq([:positive])
34
46
  end
47
+
48
+ it 'has the expected AST' do
49
+ ast.should eq([
50
+ :sub_type,
51
+ [:builtin_type, "Integer"],
52
+ [:constraint, "positive", [:fn, [:parameters, "i"], [:source, "i >= 0"]]]
53
+ ])
54
+ end
35
55
  end
36
56
 
37
57
  context '.Integer( i | positive: i >= 0, ... )' do
@@ -46,6 +66,15 @@ module Qrb
46
66
  it 'has the correct constraints' do
47
67
  compiled.constraints.keys.should eq([:positive, :small])
48
68
  end
69
+
70
+ it 'has the expected AST' do
71
+ ast.should eq([
72
+ :sub_type,
73
+ [:builtin_type, "Integer"],
74
+ [:constraint, "positive", [:fn, [:parameters, "i"], [:source, "i >= 0"]]],
75
+ [:constraint, "small", [:fn, [:parameters, "i"], [:source, "i <= 255"]]]
76
+ ])
77
+ end
49
78
  end
50
79
 
51
80
  end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ module Qrb
3
+ describe Syntax, "system" do
4
+
5
+ subject{
6
+ Syntax.parse(input, root: "system")
7
+ }
8
+
9
+ let(:ast){
10
+ subject.to_ast
11
+ }
12
+
13
+ context 'with definitions and a type' do
14
+ let(:input){ "Int = .Integer\n{r: Int}" }
15
+
16
+ it 'has the expected AST' do
17
+ ast.should eq([
18
+ :system,
19
+ [:type_def, "Int", [:builtin_type, "Integer"]],
20
+ [:tuple_type, [:heading, [:attribute, "r", [:type_ref, "Int"]]]]
21
+ ])
22
+ end
23
+ end
24
+
25
+ context 'with definitions only' do
26
+ let(:input){ "Int = .Integer" }
27
+
28
+ it 'has the expected AST' do
29
+ ast.should eq([
30
+ :system,
31
+ [:type_def, "Int", [:builtin_type, "Integer"]]
32
+ ])
33
+ end
34
+ end
35
+
36
+ context 'with a type only' do
37
+ let(:input){ "{r: .Integer}" }
38
+
39
+ it 'has the expected AST' do
40
+ ast.should eq([
41
+ :system,
42
+ [:tuple_type, [:heading, [:attribute, "r", [:builtin_type, "Integer"]]]]
43
+ ])
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -6,35 +6,53 @@ module Qrb
6
6
  Syntax.parse(input, root: "tuple_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
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 TupleType' do
18
+ compiled.should be_a(TupleType)
19
+ compiled.heading.should be_empty
20
+ end
21
+ end
12
22
 
13
- context 'empty heading' do
14
- let(:input){ '{ }' }
23
+ context '{a: .Integer}' do
24
+ let(:input){ '{a: .Integer}' }
15
25
 
16
- it 'compiles to a TupleType' do
17
- compiled.should be_a(TupleType)
18
- compiled.heading.should be_empty
26
+ it 'compiles to a TupleType' do
27
+ compiled.should be_a(TupleType)
28
+ compiled.heading.size.should eq(1)
29
+ end
19
30
  end
20
- end
21
31
 
22
- context '{a: .Integer}' do
23
- let(:input){ '{a: .Integer}' }
32
+ context '{a: .Integer, b: .Float}' do
33
+ let(:input){ '{a: .Integer, b: .Float}' }
24
34
 
25
- it 'compiles to a TupleType' do
26
- compiled.should be_a(TupleType)
27
- compiled.heading.size.should eq(1)
35
+ it 'compiles to a TupleType' do
36
+ compiled.should be_a(TupleType)
37
+ compiled.heading.size.should eq(2)
38
+ end
28
39
  end
29
40
  end
30
41
 
31
- context '{a: .Integer, b: .Float}' do
32
- let(:input){ '{a: .Integer, b: .Float}' }
42
+ describe "AST" do
43
+ let(:input){ '{a: .Integer}' }
33
44
 
34
- it 'compiles to a TupleType' do
35
- compiled.should be_a(TupleType)
36
- compiled.heading.size.should eq(2)
37
- end
45
+ let(:ast){ subject.to_ast }
46
+
47
+ it{
48
+ ast.should eq([
49
+ :tuple_type,
50
+ [
51
+ :heading,
52
+ [ :attribute, "a", [:builtin_type, "Integer" ]]
53
+ ]
54
+ ])
55
+ }
38
56
  end
39
57
 
40
58
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ module Qrb
3
+ describe Syntax, "type_def" do
4
+
5
+ subject{
6
+ Syntax.parse(input, root: "type_def")
7
+ }
8
+
9
+ let(:sys){
10
+ system
11
+ }
12
+
13
+ let(:compiled){
14
+ subject.compile(sys)
15
+ }
16
+
17
+ let(:ast){
18
+ subject.to_ast
19
+ }
20
+
21
+ let(:input){ 'Int = .Integer' }
22
+
23
+ it 'add the type to the system' do
24
+ compiled
25
+ sys["Int"].should be_a(BuiltinType)
26
+ end
27
+
28
+ it 'has the expected AST' do
29
+ ast.should eq([:type_def, "Int", [:builtin_type, "Integer"]])
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ module Qrb
3
+ describe Syntax, "type_ref" do
4
+
5
+ subject{
6
+ Syntax.parse(input, root: "type_ref")
7
+ }
8
+
9
+ let(:sys){
10
+ system
11
+ }
12
+
13
+ let(:compiled){
14
+ subject.compile(sys)
15
+ }
16
+
17
+ let(:ast){
18
+ subject.to_ast
19
+ }
20
+
21
+ before do
22
+ sys.add_type(BuiltinType.new(Integer, "Int"))
23
+ end
24
+
25
+ let(:input){ 'Int' }
26
+
27
+ it 'compiles to a the BuiltinType' do
28
+ compiled.should be_a(BuiltinType)
29
+ compiled.name.should eq("Int")
30
+ end
31
+
32
+ it 'has the expected AST' do
33
+ ast.should eq([:type_ref, "Int"])
34
+ end
35
+
36
+ end
37
+ end
@@ -6,18 +6,33 @@ module Qrb
6
6
  Syntax.parse(input, root: "union_type")
7
7
  }
8
8
 
9
- let(:compiled){
10
- subject.compile(type_factory)
11
- }
9
+ describe "compilation result" do
10
+ let(:compiled){
11
+ subject.compile(type_factory)
12
+ }
12
13
 
13
- context '.Integer|.Float' do
14
- let(:input){ '.Integer|.Float' }
14
+ context '.Integer|.Float' do
15
+ let(:input){ '.Integer|.Float' }
15
16
 
16
- it 'compiles to a UnionType' do
17
- compiled.should be_a(UnionType)
18
- compiled.should eq(UnionType.new([intType, floatType]))
17
+ it 'compiles to a UnionType' do
18
+ compiled.should be_a(UnionType)
19
+ compiled.should eq(UnionType.new([intType, floatType]))
20
+ end
19
21
  end
20
22
  end
21
23
 
24
+ describe "AST" do
25
+ let(:input){ '.Integer|.Float' }
26
+
27
+ let(:ast){ subject.to_ast }
28
+
29
+ it{ ast.should eq([
30
+ :union_type,
31
+ [:builtin_type, "Integer"],
32
+ [:builtin_type, "Float"]
33
+ ])
34
+ }
35
+ end
36
+
22
37
  end
23
38
  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
 
@@ -25,6 +29,14 @@ module Qrb
25
29
  compiled[:predicate].call(12).should be_true
26
30
  compiled[:predicate].call(9).should be_false
27
31
  end
32
+
33
+ it 'has the expected AST' do
34
+ ast.should eq([
35
+ :constraint,
36
+ "default",
37
+ [:fn, [:parameters, "a"], [:source, "a >= 10"]]
38
+ ])
39
+ end
28
40
  end
29
41
 
30
42
  end
@@ -5,8 +5,8 @@ module Qrb
5
5
  subject{ type.default_name }
6
6
 
7
7
  let(:type){
8
- AdType.new(Color, rgb: [intType, Color.method(:rgb) ],
9
- hex: [floatType, Color.method(:hex) ])
8
+ AdType.new(Color, rgb: [intType, Color.method(:rgb), Qrb::IDENTITY ],
9
+ hex: [floatType, Color.method(:hex), Qrb::IDENTITY ])
10
10
  }
11
11
 
12
12
  it{ should eq('Color') }
@@ -3,8 +3,8 @@ module Qrb
3
3
  describe AdType, 'dress' do
4
4
 
5
5
  let(:type){
6
- AdType.new(Color, rgb: [intType, ->(i){ i*2 } ],
7
- hex: [floatType, ->(f){ f*3 } ])
6
+ AdType.new(Color, rgb: [intType, ->(i){ i*2 }, Qrb::IDENTITY ],
7
+ hex: [floatType, ->(f){ f*3 }, Qrb::IDENTITY ])
8
8
  }
9
9
 
10
10
  subject{
@@ -41,7 +41,7 @@ module Qrb
41
41
 
42
42
  context 'when the upper raises an error' do
43
43
  let(:type){
44
- AdType.new(Color, rgb: [ intType, ->(t){ raise ArgumentError } ])
44
+ AdType.new(Color, rgb: [ intType, ->(t){ raise ArgumentError }, Qrb::IDENTITY ])
45
45
  }
46
46
 
47
47
  it 'should hide the error' do
@@ -3,8 +3,8 @@ module Qrb
3
3
  describe AdType, 'initialize' do
4
4
 
5
5
  subject{
6
- AdType.new(Color, rgb: [intType, Color.method(:rgb) ],
7
- hex: [floatType, Color.method(:hex) ])
6
+ AdType.new(Color, rgb: [intType, Color.method(:rgb), Qrb::IDENTITY ],
7
+ hex: [floatType, Color.method(:hex), Qrb::IDENTITY ])
8
8
  }
9
9
 
10
10
  context 'with valid arguments' do