steep 0.1.0.pre

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/README.md +95 -0
  6. data/Rakefile +23 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/bin/smoke_runner.rb +106 -0
  10. data/exe/steep +18 -0
  11. data/lib/steep.rb +33 -0
  12. data/lib/steep/annotation.rb +223 -0
  13. data/lib/steep/cli.rb +79 -0
  14. data/lib/steep/drivers/check.rb +141 -0
  15. data/lib/steep/errors.rb +207 -0
  16. data/lib/steep/interface.rb +280 -0
  17. data/lib/steep/parser.y +311 -0
  18. data/lib/steep/signature/class.rb +358 -0
  19. data/lib/steep/signature/errors.rb +78 -0
  20. data/lib/steep/signature/extension.rb +51 -0
  21. data/lib/steep/signature/interface.rb +48 -0
  22. data/lib/steep/source.rb +98 -0
  23. data/lib/steep/type_assignability.rb +362 -0
  24. data/lib/steep/type_construction.rb +993 -0
  25. data/lib/steep/type_name.rb +37 -0
  26. data/lib/steep/types.rb +4 -0
  27. data/lib/steep/types/any.rb +31 -0
  28. data/lib/steep/types/class.rb +27 -0
  29. data/lib/steep/types/instance.rb +27 -0
  30. data/lib/steep/types/merge.rb +32 -0
  31. data/lib/steep/types/name.rb +57 -0
  32. data/lib/steep/types/union.rb +42 -0
  33. data/lib/steep/types/var.rb +38 -0
  34. data/lib/steep/typing.rb +70 -0
  35. data/lib/steep/version.rb +3 -0
  36. data/manual/annotations.md +144 -0
  37. data/sig/signature.rbi +54 -0
  38. data/sig/types.rbi +43 -0
  39. data/smoke/and/a.rb +9 -0
  40. data/smoke/array/a.rb +22 -0
  41. data/smoke/block/a.rb +12 -0
  42. data/smoke/block/a.rbi +4 -0
  43. data/smoke/case/a.rb +20 -0
  44. data/smoke/class/a.rb +31 -0
  45. data/smoke/class/a.rbi +9 -0
  46. data/smoke/class/b.rb +7 -0
  47. data/smoke/class/c.rb +10 -0
  48. data/smoke/const/a.rb +30 -0
  49. data/smoke/dstr/a.rb +6 -0
  50. data/smoke/extension/a.rb +11 -0
  51. data/smoke/extension/a.rbi +8 -0
  52. data/smoke/extension/b.rb +12 -0
  53. data/smoke/extension/c.rb +9 -0
  54. data/smoke/hello/hello.rb +13 -0
  55. data/smoke/hello/hello.rbi +7 -0
  56. data/smoke/if/a.rb +20 -0
  57. data/smoke/implements/a.rb +14 -0
  58. data/smoke/implements/a.rbi +6 -0
  59. data/smoke/literal/a.rb +16 -0
  60. data/smoke/map/a.rb +5 -0
  61. data/smoke/method/a.rb +26 -0
  62. data/smoke/method/a.rbi +0 -0
  63. data/smoke/module/a.rb +21 -0
  64. data/smoke/module/a.rbi +7 -0
  65. data/smoke/module/b.rb +8 -0
  66. data/smoke/self/a.rb +23 -0
  67. data/smoke/self/a.rbi +4 -0
  68. data/smoke/super/a.rb +34 -0
  69. data/smoke/super/a.rbi +10 -0
  70. data/smoke/yield/a.rb +18 -0
  71. data/stdlib/builtin.rbi +89 -0
  72. data/steep.gemspec +32 -0
  73. metadata +214 -0
@@ -0,0 +1,37 @@
1
+ module Steep
2
+ module TypeName
3
+ class Base
4
+ attr_reader :name
5
+
6
+ def initialize(name:)
7
+ @name = name
8
+ end
9
+
10
+ def ==(other)
11
+ other.is_a?(self.class) && other.name == name
12
+ end
13
+
14
+ def hash
15
+ name.hash
16
+ end
17
+
18
+ def eql?(other)
19
+ self == other
20
+ end
21
+
22
+ def to_s
23
+ name.to_s
24
+ end
25
+ end
26
+
27
+ class Interface < Base; end
28
+
29
+ class Module < Base
30
+ def to_s
31
+ "#{name}.module"
32
+ end
33
+ end
34
+
35
+ class Instance < Base; end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module Steep
2
+ module Types
3
+ end
4
+ end
@@ -0,0 +1,31 @@
1
+ module Steep
2
+ module Types
3
+ class Any
4
+ # @implements Steep__Types__Any
5
+
6
+ def ==(other)
7
+ other.is_a?(Any)
8
+ end
9
+
10
+ def hash
11
+ self.class.hash
12
+ end
13
+
14
+ def eql?(other)
15
+ other == self
16
+ end
17
+
18
+ def closed?
19
+ true
20
+ end
21
+
22
+ def substitute(klass:, instance:, params:)
23
+ self
24
+ end
25
+
26
+ def to_s
27
+ "any"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ module Steep
2
+ module Types
3
+ class Class
4
+ # @implements Steep__Types__Class
5
+
6
+ def ==(other)
7
+ other.is_a?(Class)
8
+ end
9
+
10
+ def hash
11
+ self.class.hash
12
+ end
13
+
14
+ def eql?(other)
15
+ self == other
16
+ end
17
+
18
+ def closed?
19
+ false
20
+ end
21
+
22
+ def substitute(klass:, instance:, params:)
23
+ klass
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module Steep
2
+ module Types
3
+ class Instance
4
+ # @implements Steep__Types__Instance
5
+
6
+ def ==(other)
7
+ other.is_a?(Instance)
8
+ end
9
+
10
+ def eql?(other)
11
+ self == other
12
+ end
13
+
14
+ def hash
15
+ self.class.hash
16
+ end
17
+
18
+ def closed?
19
+ false
20
+ end
21
+
22
+ def substitute(klass:, instance:, params:)
23
+ instance
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ module Steep
2
+ module Types
3
+ class Merge
4
+ # @implements Steep__Types__Merge
5
+
6
+ # @dynamic types
7
+ attr_reader :types
8
+
9
+ def initialize(types:)
10
+ @types = types
11
+ end
12
+
13
+ def ==(other)
14
+ # @type var other_: Steep__Types__Merge
15
+ other_ = other
16
+ other_.is_a?(self.class) && other_.types == types
17
+ end
18
+
19
+ def hash
20
+ self.class.hash ^ types.hash
21
+ end
22
+
23
+ def eql?(other)
24
+ other == self
25
+ end
26
+
27
+ def to_s
28
+ types.join(" + ")
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,57 @@
1
+ module Steep
2
+ module Types
3
+ class Name
4
+ # @implements Steep__Types__Name
5
+ # @type const TypeName::Interface: Steep__TypeName.class
6
+ # @type const TypeName::Module: Steep__TypeName.class
7
+ # @type const TypeName::Instance: Steep__TypeName.class
8
+
9
+ # @dynamic name
10
+ attr_reader :name
11
+
12
+ # @dynamic params
13
+ attr_reader :params
14
+
15
+ def initialize(name:, params:)
16
+ @name = name
17
+ @params = params
18
+ end
19
+
20
+ def self.interface(name:, params: [])
21
+ self.new(name: TypeName::Interface.new(name: name), params: params)
22
+ end
23
+
24
+ def self.module(name:, params: [])
25
+ self.new(name: TypeName::Module.new(name: name), params: params)
26
+ end
27
+
28
+ def self.instance(name:, params: [])
29
+ self.new(name: TypeName::Instance.new(name: name), params: params)
30
+ end
31
+
32
+ def ==(other)
33
+ other.is_a?(Name) && name == other.name && other.params == params
34
+ end
35
+
36
+ def hash
37
+ name.hash ^ params.hash
38
+ end
39
+
40
+ def eql?(other)
41
+ other == self
42
+ end
43
+
44
+ def closed?
45
+ true
46
+ end
47
+
48
+ def substitute(klass:, instance:, params:)
49
+ self.class.new(name: name, params: self.params.map {|t| t.substitute(klass: klass, instance: instance, params: params) })
50
+ end
51
+
52
+ def to_s
53
+ "#{name}" + (params.empty? ? "" : "<#{params.map {|x| x.to_s }.join(", ")}>")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,42 @@
1
+ module Steep
2
+ module Types
3
+ class Union
4
+ # @implements Steep__Types__Union
5
+ # @type const Union: Steep__Types__Union.module
6
+
7
+ # @dynamic types
8
+ attr_reader :types
9
+
10
+ def initialize(types:)
11
+ @types = types
12
+ end
13
+
14
+ def ==(other_)
15
+ other = other_
16
+
17
+ # @type var other: Steep__Types__Union
18
+ other.is_a?(Union) && other.types.sort_by {|x| x.__id__ } == types.sort_by {|x| x.__id__ }
19
+ end
20
+
21
+ def hash
22
+ types.hash
23
+ end
24
+
25
+ def eql?(other)
26
+ self == other
27
+ end
28
+
29
+ def closed?
30
+ types.all? {|x| x.closed? }
31
+ end
32
+
33
+ def substitute(klass:, instance:, params:)
34
+ self.class.new(types: types.map {|t| t.substitute(klass: klass, instance: instance, params: params) })
35
+ end
36
+
37
+ def to_s
38
+ types.join(" | ")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module Steep
2
+ module Types
3
+ class Var
4
+ # @implements Steep__Types__Var
5
+
6
+ # @dynamic name
7
+ attr_reader :name
8
+
9
+ def initialize(name:)
10
+ @name = name
11
+ end
12
+
13
+ def ==(other)
14
+ other.is_a?(Var) && other.name == name
15
+ end
16
+
17
+ def hash
18
+ name.hash
19
+ end
20
+
21
+ def eql?(other)
22
+ self == other
23
+ end
24
+
25
+ def closed?
26
+ true
27
+ end
28
+
29
+ def substitute(klass:, instance:, params:)
30
+ params[name] || self
31
+ end
32
+
33
+ def to_s
34
+ "'#{name}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,70 @@
1
+ module Steep
2
+ class Typing
3
+ attr_reader :errors
4
+ attr_reader :typing
5
+ attr_reader :nodes
6
+ attr_reader :var_typing
7
+
8
+ def initialize
9
+ @errors = []
10
+ @nodes = {}
11
+ @var_typing = {}
12
+ @typing = {}
13
+ end
14
+
15
+ def add_error(error)
16
+ errors << error
17
+ end
18
+
19
+ def add_typing(node, type)
20
+ typing[node.__id__] = type
21
+ nodes[node.__id__] = node
22
+
23
+ type
24
+ end
25
+
26
+ def add_var_type(variable, type)
27
+ if var_typing.key?(variable)
28
+ unless var_typing[variable] == type
29
+ raise "Unexpected variable typing: existing=#{var_typing[variable]}, new=#{type}"
30
+ end
31
+ end
32
+
33
+ var_typing[variable] = type
34
+ end
35
+
36
+ def type_of(node:)
37
+ typing[node.__id__] or raise "Unknown node for typing: #{node.inspect}"
38
+ end
39
+
40
+ def type_of_variable(name: nil, label: nil)
41
+ var_typing.each do |var, type|
42
+ if (!name || var.name == name) && (!label || var.label == label)
43
+ return type
44
+ end
45
+ end
46
+
47
+ raise "Unknown variable for typing: #{name}@#{label}"
48
+ end
49
+
50
+ def dump(io)
51
+ io.puts "Typing: "
52
+ nodes.each_value do |node|
53
+ io.puts " #{Typing.summary(node)} => #{type_of(node: node).inspect}"
54
+ end
55
+
56
+ io.puts "Errors: "
57
+ errors.each do |error|
58
+ io.puts " #{Typing.summary(error.node)} => #{error.inspect}"
59
+ end
60
+ end
61
+
62
+ def self.summary(node)
63
+ src = node.loc.expression.source.split(/\n/).first
64
+ line = node.loc.first_line
65
+ col = node.loc.column
66
+
67
+ "#{line}:#{col}:#{src}"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Steep
2
+ VERSION = "0.1.0.pre"
3
+ end
@@ -0,0 +1,144 @@
1
+ # Annotations
2
+
3
+ ## Core Annotations
4
+
5
+ ### Variable type
6
+
7
+ Variable type annotation tells type of local variable.
8
+
9
+ #### Example
10
+
11
+ ```
12
+ # @type var x: String
13
+ # @type var klass: Class
14
+ ```
15
+
16
+ #### Syntax
17
+
18
+ * `@type` `var` *x* `:` *type*
19
+
20
+ ### Self type
21
+
22
+ Self type annotation tells type of `self`.
23
+
24
+ #### Example
25
+
26
+ ```
27
+ # @type self: Object
28
+ ```
29
+
30
+ #### Syntax
31
+
32
+ * `@type` `self` `:` *type*
33
+
34
+ ### Instance variable type
35
+
36
+ Instance variable type annotation tells type of instance variable.
37
+ This annotation applies to instance variable of current context.
38
+ If it's written in `module` declaration, it applies to instance variable of the module, not its instance.
39
+
40
+ #### Example
41
+
42
+ ```
43
+ # @type ivar @owner: Person
44
+ ```
45
+
46
+ #### Syntax
47
+
48
+ * `@type` `ivar` *ivar* `:` *type*
49
+
50
+ ### Global variable type
51
+
52
+ Global variable type annotation tells type of global variable.
53
+
54
+ #### Example
55
+
56
+ ```
57
+ # @type gvar $LOAD_PATH: Array<String>
58
+ ```
59
+
60
+ #### Syntax
61
+
62
+ * `@type` `gvar` *gvar* `:` *type*
63
+
64
+ ### Constant type
65
+
66
+ Constant type annotation tells type of constant.
67
+ Note that constant resolution is done syntactically.
68
+ Annotation on `File::Append` does not apply to `::File::Append`.
69
+
70
+ #### Example
71
+
72
+ ```
73
+ # @type const File::Append : Integer
74
+ ```
75
+
76
+ #### Syntax
77
+
78
+ * `@type` `const` *const* `:` *type*
79
+
80
+ ### Method type annotation
81
+
82
+ Method type annotation tells type of method being implemented in current scope.
83
+
84
+ This annotation is used to tell types of method parameters and its body.
85
+ Union method type cannot be written.
86
+
87
+ #### Example
88
+
89
+ ```
90
+ # @type method foo: (String) -> any
91
+ ```
92
+
93
+ #### Syntax
94
+
95
+ * `@type` `method` *method* `:` *single method type*
96
+
97
+ ## Module Annotations
98
+
99
+ Module annotations is about defining modules and classes in Ruby.
100
+ This kind of annotations should be written in module context.
101
+
102
+ ### Instance type annotation
103
+
104
+ Instance type annotation tells type of instance of class or module which is being defined.
105
+
106
+ #### Example
107
+
108
+ ```
109
+ # @type instance: Foo
110
+ ```
111
+
112
+ #### Syntax
113
+
114
+ * `@type` `instance` `:` *type*
115
+
116
+ ### Module type annotation
117
+
118
+ Module type annotation tells type of module of class or module which is being defined.
119
+
120
+ #### Example
121
+
122
+ ```
123
+ # @type module: Foo.class
124
+ ```
125
+
126
+ #### Syntax
127
+
128
+ * `@type` `module` `:` *type*
129
+
130
+ ### Instance/module ivar type annotation
131
+
132
+ This annotation tells instance variable of instance.
133
+
134
+ #### Example
135
+
136
+ ```
137
+ # @type instance ivar @x: String
138
+ # @type module ivar @klass: String.class
139
+ ```
140
+
141
+ #### Syntax
142
+
143
+ * `@type` `instance` `ivar` *ivar* `:` *type*
144
+ * `@type` `module` `ivar` *ivar* `:` *type*