gloss 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.gloss.yml +3 -0
- data/.rubocop.yml +147 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +112 -0
- data/README.md +205 -0
- data/Rakefile +20 -0
- data/bin/console +14 -0
- data/exe/gloss +6 -0
- data/ext/gloss/Makefile +15 -0
- data/ext/gloss/extconf.rb +32 -0
- data/ext/gloss/shard.yml +18 -0
- data/ext/gloss/src/cr_ast.cr +382 -0
- data/ext/gloss/src/gloss.cr +31 -0
- data/ext/gloss/src/lexer.cr +1186 -0
- data/ext/gloss/src/lib/cr_ruby.cr +35 -0
- data/ext/gloss/src/parser.cr +340 -0
- data/ext/gloss/src/rb_ast.cr +491 -0
- data/gloss.gemspec +26 -0
- data/lib/gloss.bundle.dwarf +0 -0
- data/lib/gloss.rb +22 -0
- data/lib/gloss/builder.rb +442 -0
- data/lib/gloss/cli.rb +35 -0
- data/lib/gloss/config.rb +15 -0
- data/lib/gloss/errors.rb +11 -0
- data/lib/gloss/initializer.rb +20 -0
- data/lib/gloss/scope.rb +9 -0
- data/lib/gloss/source.rb +32 -0
- data/lib/gloss/version.rb +3 -0
- data/lib/gloss/watcher.rb +32 -0
- data/lib/gloss/writer.rb +26 -0
- data/sig/listen.rbs +48 -0
- data/src/lib/hrb/initializer.gl +22 -0
- data/src/lib/hrb/watcher.gl +32 -0
- metadata +177 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
lib CrRuby
|
2
|
+
# every ruby Object is a VALUE
|
3
|
+
type VALUE = Void*
|
4
|
+
# ruby method typing
|
5
|
+
type METHOD_FUNC = VALUE, VALUE -> VALUE
|
6
|
+
|
7
|
+
# a ruby Class is a VALUE
|
8
|
+
$rb_cObject : VALUE
|
9
|
+
|
10
|
+
# a ruby Module is also a VALUE
|
11
|
+
$rb_mObject : VALUE
|
12
|
+
|
13
|
+
# $rb_Qnil : VALUE
|
14
|
+
|
15
|
+
# convert Ruby str to C str
|
16
|
+
fun rb_str_new_cstr(str : UInt8*) : VALUE
|
17
|
+
|
18
|
+
# convert Ruby str to plain string
|
19
|
+
fun rb_str_to_str(value: VALUE) : VALUE
|
20
|
+
|
21
|
+
# convert plain string pointer to C string pointer
|
22
|
+
fun rb_string_value_cstr(value_ptr : VALUE*) : UInt8*
|
23
|
+
|
24
|
+
# define ruby class in C
|
25
|
+
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
|
26
|
+
|
27
|
+
# define ruby module in C
|
28
|
+
fun rb_define_module(name: UInt8*) : VALUE
|
29
|
+
|
30
|
+
# define ruby method in C
|
31
|
+
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
|
32
|
+
|
33
|
+
# define singleton ruby method in C
|
34
|
+
fun rb_define_singleton_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
|
35
|
+
end
|
@@ -0,0 +1,340 @@
|
|
1
|
+
require "compiler/crystal/syntax/*"
|
2
|
+
require "./lexer"
|
3
|
+
|
4
|
+
module Gloss
|
5
|
+
class Parser < Crystal::Parser
|
6
|
+
parse_operator :or_keyword, :and_keyword, "Or.new left, right", ":or"
|
7
|
+
parse_operator :and_keyword, :prefix, "And.new left, right", ":and"
|
8
|
+
parse_operator :not_keyword, :or_keyword, "Not.new parse_prefix", ":not"
|
9
|
+
|
10
|
+
def parse_empty_array_literal
|
11
|
+
line = @line_number
|
12
|
+
column = @token.column_number
|
13
|
+
|
14
|
+
# next_token_skip_space
|
15
|
+
# next_token_skip_space_or_newline
|
16
|
+
# of = nil
|
17
|
+
Crystal::ArrayLiteral.new([] of Crystal::ASTNode) # .at_end(of)
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_hash_literal(entries, line, column, end_location, allow_of = true)
|
21
|
+
of = nil
|
22
|
+
|
23
|
+
if allow_of
|
24
|
+
if @token.keyword?(:of)
|
25
|
+
next_token_skip_space_or_newline
|
26
|
+
of_key = parse_bare_proc_type
|
27
|
+
check :"=>"
|
28
|
+
next_token_skip_space_or_newline
|
29
|
+
of_value = parse_bare_proc_type
|
30
|
+
of = Crystal::HashLiteral::Entry.new(of_key, of_value)
|
31
|
+
end_location = of_value.end_location
|
32
|
+
end
|
33
|
+
|
34
|
+
# if entries.empty? && !of
|
35
|
+
# raise "for empty hashes use '{} of KeyType => ValueType'", line, column
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
|
39
|
+
Crystal::HashLiteral.new(entries, of).at_end(end_location)
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_rescue
|
43
|
+
next_token_skip_space
|
44
|
+
|
45
|
+
if @token.type == :CONST || @token.type == :"::"
|
46
|
+
types = parse_rescue_types
|
47
|
+
skip_space
|
48
|
+
end
|
49
|
+
|
50
|
+
if @token.type == :"=>"
|
51
|
+
next_token_skip_space
|
52
|
+
end
|
53
|
+
|
54
|
+
if @token.type == :IDENT
|
55
|
+
name = @token.value.to_s
|
56
|
+
push_var_name name
|
57
|
+
next_token_skip_space
|
58
|
+
end
|
59
|
+
|
60
|
+
check SemicolonOrNewLine
|
61
|
+
|
62
|
+
next_token_skip_space_or_newline
|
63
|
+
|
64
|
+
if @token.keyword?(:end)
|
65
|
+
body = nil
|
66
|
+
else
|
67
|
+
body = parse_expressions
|
68
|
+
skip_statement_end
|
69
|
+
end
|
70
|
+
|
71
|
+
Crystal::Rescue.new(body, types, name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_rescue_types
|
75
|
+
types = [] of Crystal::ASTNode
|
76
|
+
while true
|
77
|
+
types << parse_generic
|
78
|
+
skip_space
|
79
|
+
if @token.type == :","
|
80
|
+
next_token_skip_space
|
81
|
+
else
|
82
|
+
skip_space
|
83
|
+
break
|
84
|
+
end
|
85
|
+
end
|
86
|
+
types
|
87
|
+
end
|
88
|
+
|
89
|
+
# def parse_arg(args, extra_assigns, parentheses, found_default_value, found_splat, found_double_splat, allow_restrictions)
|
90
|
+
# if @token.type == :"&"
|
91
|
+
# next_token_skip_space_or_newline
|
92
|
+
# block_arg = parse_block_arg(extra_assigns)
|
93
|
+
# skip_space_or_newline
|
94
|
+
# # When block_arg.name is empty, this is an anonymous argument.
|
95
|
+
# # An anonymous argument should not conflict other arguments names.
|
96
|
+
# # (In fact `args` may contain anonymous splat argument. See #9108).
|
97
|
+
# # So check is skipped.
|
98
|
+
# unless block_arg.name.empty?
|
99
|
+
# conflict_arg = args.any?(&.name.==(block_arg.name))
|
100
|
+
# conflict_double_splat = found_double_splat && found_double_splat.name == block_arg.name
|
101
|
+
# if conflict_arg || conflict_double_splat
|
102
|
+
# raise "duplicated argument name: #{block_arg.name}", block_arg.location.not_nil!
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
# return ArgExtras.new(block_arg, false, false, false)
|
106
|
+
# end
|
107
|
+
|
108
|
+
# if found_double_splat
|
109
|
+
# raise "only block argument is allowed after double splat"
|
110
|
+
# end
|
111
|
+
|
112
|
+
# splat = false
|
113
|
+
# double_splat = false
|
114
|
+
# arg_location = @token.location
|
115
|
+
# allow_external_name = true
|
116
|
+
|
117
|
+
# case @token.type
|
118
|
+
# when :"*"
|
119
|
+
# if found_splat
|
120
|
+
# unexpected_token
|
121
|
+
# end
|
122
|
+
|
123
|
+
# splat = true
|
124
|
+
# allow_external_name = false
|
125
|
+
# next_token_skip_space
|
126
|
+
# when :"**"
|
127
|
+
# double_splat = true
|
128
|
+
# allow_external_name = false
|
129
|
+
# next_token_skip_space
|
130
|
+
# else
|
131
|
+
# # not a splat
|
132
|
+
# end
|
133
|
+
|
134
|
+
# found_space = false
|
135
|
+
|
136
|
+
# if splat && (@token.type == :"," || @token.type == :")")
|
137
|
+
# arg_name = ""
|
138
|
+
# uses_arg = false
|
139
|
+
# allow_restrictions = false
|
140
|
+
# else
|
141
|
+
# arg_location = @token.location
|
142
|
+
# arg_name, external_name, found_space, uses_arg = parse_arg_name(arg_location, extra_assigns, allow_external_name: allow_external_name)
|
143
|
+
|
144
|
+
# args.each do |arg|
|
145
|
+
# if arg.name == arg_name
|
146
|
+
# raise "duplicated argument name: #{arg_name}", arg_location
|
147
|
+
# end
|
148
|
+
|
149
|
+
# if arg.external_name == external_name
|
150
|
+
# raise "duplicated argument external name: #{external_name}", arg_location
|
151
|
+
# end
|
152
|
+
# end
|
153
|
+
|
154
|
+
# if @token.type == :SYMBOL
|
155
|
+
# raise "space required after colon in type restriction", @token
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
|
159
|
+
# default_value = nil
|
160
|
+
# restriction = nil
|
161
|
+
# keyword_argument = @token.type == :":" && !found_space
|
162
|
+
|
163
|
+
# found_colon = false
|
164
|
+
|
165
|
+
# next_token_skip_space
|
166
|
+
|
167
|
+
# if allow_restrictions && @token.type == :":"
|
168
|
+
|
169
|
+
# next_token_skip_space_or_newline
|
170
|
+
|
171
|
+
# location = @token.location
|
172
|
+
# splat_restriction = false
|
173
|
+
# if (splat && @token.type == :"*") || (double_splat && @token.type == :"**")
|
174
|
+
# splat_restriction = true
|
175
|
+
# next_token
|
176
|
+
# end
|
177
|
+
|
178
|
+
# restriction = parse_bare_proc_type
|
179
|
+
|
180
|
+
# if splat_restriction
|
181
|
+
# restriction = splat ? Crystal::Splat.new(restriction) : Crystal::DoubleSplat.new(restriction)
|
182
|
+
# restriction.at(location)
|
183
|
+
# end
|
184
|
+
# found_colon = true
|
185
|
+
# end
|
186
|
+
|
187
|
+
# if @token.type == :"="
|
188
|
+
# raise "splat argument can't have default value", @token if splat
|
189
|
+
# raise "double splat argument can't have default value", @token if double_splat
|
190
|
+
|
191
|
+
# slash_is_regex!
|
192
|
+
# next_token_skip_space_or_newline
|
193
|
+
|
194
|
+
# case @token.type
|
195
|
+
# when :__LINE__, :__END_LINE__, :__FILE__, :__DIR__
|
196
|
+
# default_value = Crystal::MagicConstant.new(@token.type).at(@token.location)
|
197
|
+
# next_token
|
198
|
+
# else
|
199
|
+
# @no_type_declaration += 1
|
200
|
+
# default_value = parse_op_assign
|
201
|
+
# @no_type_declaration -= 1
|
202
|
+
# end
|
203
|
+
|
204
|
+
# skip_space
|
205
|
+
# else
|
206
|
+
# if found_default_value && !found_splat && !splat && !double_splat
|
207
|
+
# raise "argument must have a default value", arg_location
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
# unless found_colon
|
212
|
+
# if @token.type == :SYMBOL
|
213
|
+
# raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
|
214
|
+
# end
|
215
|
+
|
216
|
+
# if allow_restrictions && @token.type == :":"
|
217
|
+
# raise "the syntax for an argument with a default value V and type T is `arg : T = V`", @token
|
218
|
+
# end
|
219
|
+
# end
|
220
|
+
|
221
|
+
# raise "BUG: arg_name is nil" unless arg_name
|
222
|
+
|
223
|
+
# arg = Crystal::Arg.new(arg_name, default_value, restriction, external_name: external_name).at(arg_location)
|
224
|
+
# arg.keyword_arg = keyword_argument
|
225
|
+
# args << arg
|
226
|
+
# push_var arg
|
227
|
+
|
228
|
+
# Crystal::Parser::ArgExtras.new(nil, !!default_value, splat, !!double_splat)
|
229
|
+
# end
|
230
|
+
|
231
|
+
#def parse_arg_name(location, extra_assigns, allow_external_name)
|
232
|
+
# do_next_token = true
|
233
|
+
# found_string_literal = false
|
234
|
+
# invalid_internal_name = nil
|
235
|
+
|
236
|
+
# if allow_external_name && (@token.type == :IDENT || string_literal_start?)
|
237
|
+
# if @token.type == :IDENT
|
238
|
+
# if @token.keyword? && invalid_internal_name?(@token.value)
|
239
|
+
# invalid_internal_name = @token.dup
|
240
|
+
# end
|
241
|
+
# external_name = @token.type == :IDENT ? @token.value.to_s : ""
|
242
|
+
# next_token
|
243
|
+
# else
|
244
|
+
# external_name = parse_string_without_interpolation("external name")
|
245
|
+
# found_string_literal = true
|
246
|
+
# end
|
247
|
+
# found_space = @token.type == :SPACE || @token.type == :NEWLINE
|
248
|
+
# skip_space
|
249
|
+
# do_next_token = false
|
250
|
+
# end
|
251
|
+
|
252
|
+
# case @token.type
|
253
|
+
# when :IDENT
|
254
|
+
# if @token.keyword? && invalid_internal_name?(@token.value)
|
255
|
+
# raise "cannot use '#{@token}' as an argument name", @token
|
256
|
+
# end
|
257
|
+
|
258
|
+
# arg_name = @token.value.to_s
|
259
|
+
# if arg_name == external_name
|
260
|
+
# raise "when specified, external name must be different than internal name", @token
|
261
|
+
# end
|
262
|
+
|
263
|
+
# uses_arg = false
|
264
|
+
# do_next_token = true
|
265
|
+
# when :INSTANCE_VAR
|
266
|
+
# arg_name = @token.value.to_s[1..-1]
|
267
|
+
# if arg_name == external_name
|
268
|
+
# raise "when specified, external name must be different than internal name", @token
|
269
|
+
# end
|
270
|
+
|
271
|
+
# # If it's something like @select, we can't transform it to:
|
272
|
+
# #
|
273
|
+
# # @select = select
|
274
|
+
# #
|
275
|
+
# # because if someone uses `to_s` later it will produce invalid code.
|
276
|
+
# # So we do something like:
|
277
|
+
# #
|
278
|
+
# # def method(select __arg0)
|
279
|
+
# # @select = __arg0
|
280
|
+
# # end
|
281
|
+
# if !external_name && invalid_internal_name?(arg_name)
|
282
|
+
# arg_name, external_name = temp_arg_name, arg_name
|
283
|
+
# end
|
284
|
+
|
285
|
+
# ivar = Crystal::InstanceVar.new(@token.value.to_s).at(location)
|
286
|
+
# var = Crystal::Var.new(arg_name).at(location)
|
287
|
+
# assign = Crystal::Assign.new(ivar, var).at(location)
|
288
|
+
# if extra_assigns
|
289
|
+
# extra_assigns.push assign
|
290
|
+
# else
|
291
|
+
# raise "can't use @instance_variable here"
|
292
|
+
# end
|
293
|
+
# uses_arg = true
|
294
|
+
# do_next_token = true
|
295
|
+
# when :CLASS_VAR
|
296
|
+
# arg_name = @token.value.to_s[2..-1]
|
297
|
+
# if arg_name == external_name
|
298
|
+
# raise "when specified, external name must be different than internal name", @token
|
299
|
+
# end
|
300
|
+
|
301
|
+
# # Same case as :INSTANCE_VAR for things like @select
|
302
|
+
# if !external_name && invalid_internal_name?(arg_name)
|
303
|
+
# arg_name, external_name = temp_arg_name, arg_name
|
304
|
+
# end
|
305
|
+
|
306
|
+
# cvar = Crystal::ClassVar.new(@token.value.to_s).at(location)
|
307
|
+
# var = Crystal::Var.new(arg_name).at(location)
|
308
|
+
# assign = Crystal::Assign.new(cvar, var).at(location)
|
309
|
+
# if extra_assigns
|
310
|
+
# extra_assigns.push assign
|
311
|
+
# else
|
312
|
+
# raise "can't use @@class_var here"
|
313
|
+
# end
|
314
|
+
# uses_arg = true
|
315
|
+
# do_next_token = true
|
316
|
+
# else
|
317
|
+
# if external_name
|
318
|
+
# if found_string_literal
|
319
|
+
# raise "unexpected token: #{@token}, expected argument internal name"
|
320
|
+
# end
|
321
|
+
# if invalid_internal_name
|
322
|
+
# raise "cannot use '#{invalid_internal_name}' as an argument name", invalid_internal_name
|
323
|
+
# end
|
324
|
+
# arg_name = external_name
|
325
|
+
# else
|
326
|
+
# raise "unexpected token: #{@token}"
|
327
|
+
# end
|
328
|
+
# end
|
329
|
+
|
330
|
+
# if do_next_token
|
331
|
+
# next_token
|
332
|
+
# found_space = @token.type == :SPACE || @token.type == :NEWLINE
|
333
|
+
# end
|
334
|
+
|
335
|
+
# skip_space
|
336
|
+
|
337
|
+
# {arg_name, external_name, found_space, uses_arg}
|
338
|
+
#end
|
339
|
+
end
|
340
|
+
end
|
@@ -0,0 +1,491 @@
|
|
1
|
+
require "compiler/crystal/syntax/*"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Rb
|
5
|
+
class AST
|
6
|
+
enum RbLiteral
|
7
|
+
String
|
8
|
+
Integer
|
9
|
+
TrueClass
|
10
|
+
FalseClass
|
11
|
+
NilClass
|
12
|
+
Float
|
13
|
+
Symbol
|
14
|
+
end
|
15
|
+
|
16
|
+
abstract class Node
|
17
|
+
end
|
18
|
+
|
19
|
+
abstract class NodeWithChildren < Node
|
20
|
+
@info : NamedTuple(type: String, children: Array(Node))
|
21
|
+
|
22
|
+
def initialize(@children : Array(Node))
|
23
|
+
@info = {
|
24
|
+
type: self.class.name.split("::").last,
|
25
|
+
children: @children,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
delegate :to_json, to: @info
|
30
|
+
end
|
31
|
+
|
32
|
+
abstract class NodeWithValue < Node
|
33
|
+
@info : NamedTuple(type: String, value: String)
|
34
|
+
|
35
|
+
def initialize(@value : String)
|
36
|
+
@info = {
|
37
|
+
type: self.class.name.split("::").last,
|
38
|
+
value: @value,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
delegate :to_json, to: @info
|
43
|
+
end
|
44
|
+
|
45
|
+
class Block < Node
|
46
|
+
@info : NamedTuple(type: String, args: Array(Var), body: Node)
|
47
|
+
|
48
|
+
def initialize(args, body)
|
49
|
+
@info = {
|
50
|
+
type: self.class.name.split("::").last,
|
51
|
+
body: body,
|
52
|
+
args: args,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
delegate :to_json, to: @info
|
57
|
+
end
|
58
|
+
|
59
|
+
class CollectionNode < NodeWithChildren
|
60
|
+
end
|
61
|
+
|
62
|
+
class ClassNode < Node
|
63
|
+
@info : NamedTuple(type: String, name: Path, body: Node, superclass: Node?, type_vars: Array(String)?, abstract: Bool)
|
64
|
+
|
65
|
+
def initialize(name : Path, body : Node, superclass : Node?, type_vars : Array(String)?, abstr : Bool)
|
66
|
+
@info = {
|
67
|
+
type: self.class.name.split("::").last,
|
68
|
+
name: name,
|
69
|
+
body: body,
|
70
|
+
superclass: superclass,
|
71
|
+
type_vars: type_vars,
|
72
|
+
abstract: abstr,
|
73
|
+
# visibility: vis,
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
delegate :to_json, to: @info
|
78
|
+
end
|
79
|
+
|
80
|
+
class ModuleNode < Node
|
81
|
+
@info : NamedTuple(type: String, name: Path, body: Node, type_vars: Array(String)?)
|
82
|
+
|
83
|
+
def initialize(name : Path, body : Node, type_vars : Array(String)?)
|
84
|
+
@info = {
|
85
|
+
type: self.class.name.split("::").last,
|
86
|
+
name: name,
|
87
|
+
body: body,
|
88
|
+
type_vars: type_vars,
|
89
|
+
# visiblity: vis,
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
delegate :to_json, to: @info
|
94
|
+
end
|
95
|
+
|
96
|
+
class DefNode < Node
|
97
|
+
@info : NamedTuple(type: String, name: String, body: Node, rp_args: Array(Arg), receiver: Node?,
|
98
|
+
return_type: Node?, rest_kw_args: Arg?)
|
99
|
+
|
100
|
+
def initialize(name : String, rp_args : Array(Arg), body : Node, receiver : Node?, return_type : Node?, rest_kw_args)
|
101
|
+
@info = {
|
102
|
+
type: self.class.name.split("::").last,
|
103
|
+
name: name,
|
104
|
+
body: body,
|
105
|
+
rp_args: rp_args,
|
106
|
+
rest_kw_args: rest_kw_args,
|
107
|
+
receiver: receiver,
|
108
|
+
return_type: return_type,
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
delegate :to_json, to: @info
|
113
|
+
end
|
114
|
+
|
115
|
+
class Arg < Node
|
116
|
+
@info : NamedTuple(type: String, name: String, external_name: String, default_value: Node?,
|
117
|
+
restriction: Node?)
|
118
|
+
|
119
|
+
def initialize(name : String, external_name : String, restriction : Node?, default_value : Node?)
|
120
|
+
@info = {
|
121
|
+
type: self.class.name.split("::").last,
|
122
|
+
name: name,
|
123
|
+
restriction: restriction,
|
124
|
+
default_value: default_value,
|
125
|
+
external_name: external_name,
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
delegate :to_json, to: @info
|
130
|
+
end
|
131
|
+
|
132
|
+
class LiteralNode < Node
|
133
|
+
@info : NamedTuple(type: String, value: String | Int32 | Bool | Nil, rb_type: String)
|
134
|
+
|
135
|
+
def initialize(value, rb_type : RbLiteral)
|
136
|
+
val = case rb_type
|
137
|
+
when Rb::AST::RbLiteral::TrueClass
|
138
|
+
true
|
139
|
+
when Rb::AST::RbLiteral::FalseClass
|
140
|
+
false
|
141
|
+
when Rb::AST::RbLiteral::NilClass
|
142
|
+
nil
|
143
|
+
when Rb::AST::RbLiteral::Symbol
|
144
|
+
":#{value}"
|
145
|
+
else
|
146
|
+
value
|
147
|
+
end
|
148
|
+
@info = {
|
149
|
+
type: self.class.name.split("::").last,
|
150
|
+
value: value,
|
151
|
+
rb_type: rb_type.inspect,
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
delegate :to_json, to: @info
|
156
|
+
end
|
157
|
+
|
158
|
+
class ArrayLiteral < Node
|
159
|
+
@info : NamedTuple(type: String, elements: Array(Node), frozen: Bool)
|
160
|
+
|
161
|
+
def initialize(elems, frozen = false)
|
162
|
+
@info = {
|
163
|
+
type: self.class.name.split("::").last,
|
164
|
+
elements: elems,
|
165
|
+
frozen: frozen,
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
delegate :to_json, to: @info
|
170
|
+
end
|
171
|
+
|
172
|
+
class HashLiteral < Node
|
173
|
+
@info : NamedTuple(type: String, elements: Array(Tuple(Node, Node)) | Array(Tuple(String, Node)), frozen: Bool)
|
174
|
+
|
175
|
+
def initialize(elems, frozen = false)
|
176
|
+
@info = {
|
177
|
+
type: self.class.name.split("::").last,
|
178
|
+
elements: elems,
|
179
|
+
frozen: frozen,
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
delegate :to_json, to: @info
|
184
|
+
end
|
185
|
+
|
186
|
+
class RangeLiteral < Node
|
187
|
+
@info : NamedTuple(type: String, from: Node, to: Node, exclusive: Bool)
|
188
|
+
|
189
|
+
def initialize(from, to, exclusive)
|
190
|
+
@info = {
|
191
|
+
type: self.class.name.split("::").last,
|
192
|
+
from: from,
|
193
|
+
to: to,
|
194
|
+
exclusive: exclusive,
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
delegate :to_json, to: @info
|
199
|
+
end
|
200
|
+
|
201
|
+
class RegexLiteral < NodeWithValue
|
202
|
+
end
|
203
|
+
|
204
|
+
class Nop < Node
|
205
|
+
@info : NamedTuple(type: String)?
|
206
|
+
|
207
|
+
def initialize
|
208
|
+
@info = nil
|
209
|
+
end
|
210
|
+
|
211
|
+
delegate :to_json, to: @info
|
212
|
+
end
|
213
|
+
|
214
|
+
class EmptyNode < Nop
|
215
|
+
def initialize(class_name : String)
|
216
|
+
STDERR.puts "Encountered a ruby EmptyNode class name: #{class_name}"
|
217
|
+
@info = {
|
218
|
+
type: self.class.name.split("::").last,
|
219
|
+
}
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
class Var < Node
|
224
|
+
@info : NamedTuple(type: String, name: String)
|
225
|
+
|
226
|
+
def initialize(@name : String)
|
227
|
+
@info = {
|
228
|
+
type: self.class.name.split("::").last,
|
229
|
+
name: @name,
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
delegate :to_json, to: @info
|
234
|
+
end
|
235
|
+
|
236
|
+
class InstanceVar < Var
|
237
|
+
end
|
238
|
+
|
239
|
+
abstract class Conditional < Node
|
240
|
+
@info : NamedTuple(type: String, condition: Node, then: Node, else: Node)
|
241
|
+
|
242
|
+
def initialize(@condition : Node, @thn : Node, @els : Node)
|
243
|
+
@info = {
|
244
|
+
type: self.class.name.split("::").last,
|
245
|
+
condition: @condition,
|
246
|
+
then: @thn,
|
247
|
+
else: @els,
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
delegate :to_json, to: @info
|
252
|
+
end
|
253
|
+
|
254
|
+
class If < Conditional
|
255
|
+
end
|
256
|
+
|
257
|
+
class Unless < Conditional
|
258
|
+
end
|
259
|
+
|
260
|
+
class Case < Node
|
261
|
+
@info : NamedTuple(type: String, condition: Node?, whens: Array(When), else: Node?, exhaustive: Bool)
|
262
|
+
|
263
|
+
def initialize(cond : Node?, whens : Array(When), els : Node?, exhaustive : Bool)
|
264
|
+
@info = {
|
265
|
+
type: self.class.name.split("::").last,
|
266
|
+
condition: cond,
|
267
|
+
whens: whens,
|
268
|
+
else: els,
|
269
|
+
exhaustive: exhaustive,
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
delegate :to_json, to: @info
|
274
|
+
end
|
275
|
+
|
276
|
+
class When < Node
|
277
|
+
@info : NamedTuple(type: String, conditions: Array(Node), body: Node, exhaustive: Bool)
|
278
|
+
|
279
|
+
def initialize(conds : Array(Node), body : Node, exhaustive : Bool)
|
280
|
+
@info = {
|
281
|
+
type: self.class.name.split("::").last,
|
282
|
+
conditions: conds,
|
283
|
+
body: body,
|
284
|
+
exhaustive: exhaustive,
|
285
|
+
}
|
286
|
+
end
|
287
|
+
|
288
|
+
delegate :to_json, to: @info
|
289
|
+
end
|
290
|
+
|
291
|
+
class Enum < Node
|
292
|
+
@info : NamedTuple(type: String, name: Crystal::Path, members: Array(Node))
|
293
|
+
|
294
|
+
def initialize(@name : Crystal::Path, @members : Array(Node))
|
295
|
+
@info = {
|
296
|
+
type: self.class.name.split("::").last,
|
297
|
+
name: @name,
|
298
|
+
members: @members,
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
delegate :to_json, to: @info
|
303
|
+
end
|
304
|
+
|
305
|
+
class Call < Node
|
306
|
+
@info : NamedTuple(type: String, name: String, args: Array(Node), object: Node?, block: Block?, block_arg: Node?)
|
307
|
+
|
308
|
+
def initialize(object : Node?, name : String, args : Array(Node), block, block_arg)
|
309
|
+
@info = {
|
310
|
+
type: self.class.name.split("::").last,
|
311
|
+
name: name,
|
312
|
+
args: args,
|
313
|
+
object: object,
|
314
|
+
block: block,
|
315
|
+
block_arg: block_arg,
|
316
|
+
}
|
317
|
+
end
|
318
|
+
|
319
|
+
delegate :to_json, to: @info
|
320
|
+
end
|
321
|
+
|
322
|
+
class Path < NodeWithValue
|
323
|
+
end
|
324
|
+
|
325
|
+
class Require < NodeWithValue
|
326
|
+
end
|
327
|
+
|
328
|
+
class StringInterpolation < Node
|
329
|
+
@info : NamedTuple(type: String, contents: Array(Node))
|
330
|
+
|
331
|
+
def initialize(contents)
|
332
|
+
@info = {
|
333
|
+
type: self.class.name.split("::").last,
|
334
|
+
contents: contents,
|
335
|
+
}
|
336
|
+
end
|
337
|
+
|
338
|
+
delegate :to_json, to: @info
|
339
|
+
end
|
340
|
+
|
341
|
+
class UnaryExpr < Node
|
342
|
+
@info : NamedTuple(type: String, op: String, value: Node, with_parens: Bool)
|
343
|
+
|
344
|
+
def initialize(val, op, parens)
|
345
|
+
@info = {
|
346
|
+
type: self.class.name.split("::").last,
|
347
|
+
value: val,
|
348
|
+
op: op,
|
349
|
+
with_parens: parens,
|
350
|
+
}
|
351
|
+
end
|
352
|
+
|
353
|
+
delegate :to_json, to: @info
|
354
|
+
end
|
355
|
+
|
356
|
+
class BinaryOp < Node
|
357
|
+
@info : NamedTuple(type: String, op: String, left: Node, right: Node)
|
358
|
+
|
359
|
+
def initialize(op, left, right)
|
360
|
+
@info = {
|
361
|
+
type: self.class.name.split("::").last,
|
362
|
+
left: left,
|
363
|
+
op: op,
|
364
|
+
right: right,
|
365
|
+
}
|
366
|
+
end
|
367
|
+
|
368
|
+
delegate :to_json, to: @info
|
369
|
+
end
|
370
|
+
|
371
|
+
class Assign < Node
|
372
|
+
@info : NamedTuple(type: String, op: String?, target: Node, value: Node)
|
373
|
+
|
374
|
+
def initialize(target, value, op = nil)
|
375
|
+
@info = {
|
376
|
+
type: self.class.name.split("::").last,
|
377
|
+
target: target,
|
378
|
+
op: op,
|
379
|
+
value: value,
|
380
|
+
}
|
381
|
+
end
|
382
|
+
|
383
|
+
delegate :to_json, to: @info
|
384
|
+
end
|
385
|
+
|
386
|
+
class TypeDeclaration < Node
|
387
|
+
@info : NamedTuple(type: String, var: Node, declared_type: Node, value: Node?, var_type: String)
|
388
|
+
|
389
|
+
def initialize(@var : Node, @declared_type : Node, @value : Node?)
|
390
|
+
@info = {
|
391
|
+
type: self.class.name.split("::").last,
|
392
|
+
var: @var,
|
393
|
+
var_type: @var.class.name.split("::").last,
|
394
|
+
declared_type: @declared_type,
|
395
|
+
value: @value,
|
396
|
+
}
|
397
|
+
end
|
398
|
+
|
399
|
+
delegate :to_json, to: @info
|
400
|
+
end
|
401
|
+
|
402
|
+
class MacroFor < Node
|
403
|
+
@info : NamedTuple(type: String, vars: Array(Var), expr: Node, body: Node)
|
404
|
+
|
405
|
+
def initialize(vars, expr, body)
|
406
|
+
@info = {
|
407
|
+
type: self.class.name.split("::").last,
|
408
|
+
vars: vars,
|
409
|
+
expr: expr,
|
410
|
+
body: body,
|
411
|
+
}
|
412
|
+
end
|
413
|
+
|
414
|
+
delegate :to_json, to: @info
|
415
|
+
end
|
416
|
+
|
417
|
+
class MacroIf < Conditional
|
418
|
+
end
|
419
|
+
|
420
|
+
class MacroLiteral < NodeWithValue
|
421
|
+
end
|
422
|
+
|
423
|
+
class MacroExpression < Node
|
424
|
+
@info : NamedTuple(type: String, expr: Node, output: Bool)
|
425
|
+
|
426
|
+
def initialize(expr, output)
|
427
|
+
@info = {
|
428
|
+
type: self.class.name.split("::").last,
|
429
|
+
expr: expr,
|
430
|
+
output: output,
|
431
|
+
}
|
432
|
+
end
|
433
|
+
|
434
|
+
delegate :to_json, to: @info
|
435
|
+
end
|
436
|
+
|
437
|
+
class ControlExpression < Node
|
438
|
+
@info : NamedTuple(type: String, value: Node?)
|
439
|
+
|
440
|
+
def initialize(value)
|
441
|
+
@info = {
|
442
|
+
type: self.class.name.split("::").last,
|
443
|
+
value: value,
|
444
|
+
}
|
445
|
+
end
|
446
|
+
|
447
|
+
delegate :to_json, to: @info
|
448
|
+
end
|
449
|
+
|
450
|
+
class Return < ControlExpression
|
451
|
+
end
|
452
|
+
|
453
|
+
class Break < ControlExpression
|
454
|
+
end
|
455
|
+
|
456
|
+
class Next < ControlExpression
|
457
|
+
end
|
458
|
+
|
459
|
+
class ExceptionHandler < Node
|
460
|
+
@info : NamedTuple(type: String, body: Node, rescues: Array(Rescue)?, else: Node?,
|
461
|
+
ensure: Node?)
|
462
|
+
|
463
|
+
def initialize(body, rescues, else_node, ensure_node)
|
464
|
+
@info = {
|
465
|
+
type: self.class.name.split("::").last,
|
466
|
+
body: body,
|
467
|
+
rescues: rescues,
|
468
|
+
else: else_node,
|
469
|
+
ensure: ensure_node,
|
470
|
+
}
|
471
|
+
end
|
472
|
+
|
473
|
+
delegate :to_json, to: @info
|
474
|
+
end
|
475
|
+
|
476
|
+
class Rescue < Node
|
477
|
+
@info : NamedTuple(type: String, body: Node, types: Array(Node)?, name: String?)
|
478
|
+
|
479
|
+
def initialize(body, types, name)
|
480
|
+
@info = {
|
481
|
+
type: self.class.name.split("::").last,
|
482
|
+
body: body,
|
483
|
+
types: types,
|
484
|
+
name: name,
|
485
|
+
}
|
486
|
+
end
|
487
|
+
|
488
|
+
delegate :to_json, to: @info
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|