gloss 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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