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.
@@ -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