syntax: break closures are implicitly ended with 'break'
[nit.git] / src / syntax / icode_generation.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Things needed by typing.nit to generate intermediate code from AST
18 package icode_generation
19
20 import icode
21 import syntax_base
22 private import typing
23 private import primitive_info
24
25 # An AST2ICode context stores the currently built icode informations
26 class A2IContext
27 special ICodeBuilder
28 redef fun stmt(s: ICode)
29 do
30 if _current_node != null then
31 current_location = _current_node.location
32 else if visitor.current_node != null then
33 current_location = visitor.current_node.location
34 end
35 super
36 end
37
38 # Prepare a new array of length item
39 fun add_new_array(stype: MMType, length: Int): IRegister
40 do
41 var prop = visitor.get_method(stype, once "with_capacity".to_symbol)
42 var ni = expr(new INative("TAG_Int({length})", null), visitor.type_int)
43 return expr(new INew(stype, prop, [ni]), stype)
44 end
45
46 # Add an array add
47 fun add_call_array_add(recv, item: IRegister)
48 do
49 var stype = recv.stype
50 var prop = visitor.get_method(stype, once "add".to_symbol)
51 stmt(new ICall(prop, [recv, item]))
52 end
53
54 # Get the iregister associated with a variable
55 # Or assign one if none exists
56 fun variable(v: Variable): IRegister
57 do
58 if _variables.has_key(v) then
59 return _variables[v]
60 else
61 var t = v.stype
62 if t == null then t = visitor.type_object.as_nullable
63 var reg = new_register(t)
64 _variables[v] = reg
65 return reg
66 end
67 end
68
69 # Current registered variable
70 var _variables: HashMap[Variable, IRegister] = new HashMap[Variable, IRegister]
71
72 # Current registered closurevariables
73 readable var _closurevariables: HashMap[ClosureVariable, IClosureDecl] = new HashMap[ClosureVariable, IClosureDecl]
74
75 # The current syntax visitor
76 readable var _visitor: AbsSyntaxVisitor
77
78 # Where a nit return must branch
79 readable writable var _return_seq: nullable ISeq
80
81 # Register where a functionnal nit return must store its value
82 readable writable var _return_value: nullable IRegister
83
84 # The method associated to the iroutine (if any)
85 readable var _method: nullable MMMethod
86
87 init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
88 do
89 super(visitor.module, r)
90 _visitor = visitor
91 _return_seq = r.body
92 _return_value = r.result
93 _method = m
94 end
95
96 # Insert implicit super init calls
97 fun invoke_super_init_calls_after(start_prop: nullable MMMethod)
98 do
99 var p = method
100 assert p isa MMSrcMethod
101 var n = p.node
102 assert n isa AConcreteInitPropdef
103
104 if n.super_init_calls.is_empty then return
105 var i = 0
106 var j = 0
107 if start_prop != null then
108 while n.super_init_calls[i] != start_prop do
109 i += 1
110 end
111 i += 1
112
113 while n.explicit_super_init_calls[j] != start_prop do
114 j += 1
115 end
116 j += 1
117 end
118 var stop_prop: nullable MMMethod = null
119 if j < n.explicit_super_init_calls.length then
120 stop_prop = n.explicit_super_init_calls[j]
121 end
122 var l = n.super_init_calls.length
123 while i < l do
124 var sp = n.super_init_calls[i]
125 if sp == stop_prop then break
126 var cargs = new Array[IRegister]
127 if sp.signature.arity == 0 then
128 cargs.add(iroutine.params.first)
129 else
130 for va in iroutine.params do
131 cargs.add(va)
132 end
133 end
134 stmt(new ICall(sp, cargs))
135 i += 1
136 end
137 end
138
139 # The current AExpr
140 var _current_node: nullable AExpr = null
141
142 # Generate icode in the current sequence from a statement
143 fun generate_stmt(n: nullable AExpr)
144 do
145 if n == null then return
146 var old = _current_node
147 _current_node = n
148 n.generate_icode(self)
149 _current_node = old
150 end
151
152 # Generate icode in the current sequence from an expression
153 fun generate_expr(n: AExpr): IRegister
154 do
155 var old = _current_node
156 _current_node = n
157 var reg = n.generate_icode(self).as(not null)
158 _current_node = old
159 return reg
160 end
161 end
162
163 redef class EscapableBlock
164 # Where a nit break must branch
165 readable writable var _break_seq: nullable ISeq
166
167 # Where a nit continue must branch
168 readable writable var _continue_seq: nullable ISeq
169
170 # Register where a functionnal nit break must store its value
171 readable writable var _break_value: nullable IRegister
172
173 # Register where a functionnal nit continue must store its value
174 readable writable var _continue_value: nullable IRegister
175 end
176
177 redef class MMSrcModule
178 # Generate icode for method bodies
179 fun generate_icode(tc: ToolContext)
180 do
181 var v = new A2IVisitor(tc, self)
182 for c in src_local_classes do
183 for p in c.src_local_properties do
184 if p isa MMSrcMethod then
185 p.generate_iroutine(v)
186 else if p isa MMSrcAttribute then
187 p.generate_iroutine(v)
188 end
189 end
190 end
191 end
192 end
193
194 redef class MMSrcAttribute
195 redef readable writable var _iroutine: nullable IRoutine
196
197 # Generate the initialization iroutine
198 fun generate_iroutine(visitor: A2IVisitor)
199 do
200 if node.n_expr != null then
201 var iroutine = signature.generate_empty_iroutine
202 iroutine.location = node.location
203 var v = new A2IContext(visitor, iroutine, null)
204 visitor.icode_ctx = v
205 visitor.enter_visit(node)
206 visitor.icode_ctx = null
207 _iroutine = iroutine
208 end
209 end
210 end
211
212 redef class MMSrcMethod
213 redef readable writable var _iroutine: nullable IRoutine
214
215 # Generate the body iroutine
216 fun generate_iroutine(visitor: A2IVisitor)
217 do
218 var iroutine = signature.generate_empty_iroutine
219 if node != null then
220 iroutine.location = node.location
221 end
222 var v = new A2IContext(visitor, iroutine, self)
223 visitor.icode_ctx = v
224 inner_generate_iroutine(v)
225 visitor.icode_ctx = null
226 _iroutine = iroutine
227 end
228
229 # Generate the body iroutine (specific part)
230 fun inner_generate_iroutine(v: A2IContext) is abstract
231 end
232
233 redef class MMReadImplementationMethod
234 redef fun inner_generate_iroutine(v)
235 do
236 var e = v.add_attr_read(node.prop, v.iroutine.params.first)
237 v.add_return_value(e)
238 end
239 end
240
241 redef class MMWriteImplementationMethod
242 redef fun inner_generate_iroutine(v)
243 do
244 var params = v.iroutine.params
245 v.stmt(new IAttrWrite(node.prop, params[0], params[1]))
246 end
247 end
248
249 redef class MMMethSrcMethod
250 redef fun inner_generate_iroutine(v)
251 do
252 v.visitor.enter_visit(node)
253 end
254 end
255
256 redef class MMImplicitInit
257 redef fun inner_generate_iroutine(v)
258 do
259 var params = v.iroutine.params
260 var f = params.length - unassigned_attributes.length
261 var recv = params.first
262 for sp in super_inits do
263 assert sp isa MMMethod
264 var args_recv = [recv]
265 if sp == super_init then
266 var args = new Array[IRegister].with_capacity(f)
267 args.add(recv)
268 for i in [1..f[ do
269 args.add(params[i])
270 end
271 v.stmt(new ICall(sp, args))
272 else
273 v.stmt(new ICall(sp, args_recv))
274 end
275 end
276 for i in [f..params.length[ do
277 var attribute = unassigned_attributes[i-f]
278 v.stmt(new IAttrWrite(attribute, recv, params[i]))
279 end
280 end
281 end
282
283 class A2IVisitor
284 special AbsSyntaxVisitor
285 writable var _icode_ctx: nullable A2IContext
286 fun icode_ctx: A2IContext do return _icode_ctx.as(not null)
287 redef fun visit(n) do n.accept_icode_generation(self)
288 init(tc, m) do super
289 end
290
291
292 ###############################################################################
293
294 redef class ANode
295 fun accept_icode_generation(v: A2IVisitor) do accept_abs_syntax_visitor(v) end
296 end
297
298 redef class AAttrPropdef
299 redef fun accept_icode_generation(vv)
300 do
301 var v = vv.icode_ctx
302 v.stmt(new IMove(v.variable(self_var), v.iroutine.params.first))
303 super
304 var ne = n_expr
305 if ne != null then
306 v.stmt(new IMove(v.iroutine.result.as(not null), v.generate_expr(ne)))
307 end
308 end
309 end
310
311 redef class AMethPropdef
312 redef fun accept_icode_generation(vv)
313 do
314 super
315 fill_iroutine(vv.icode_ctx, method)
316 end
317
318 # Compile the method body common preambule (before specific body stuff if any)
319 fun fill_iroutine(v: A2IContext, method: MMSrcMethod) is abstract
320 end
321
322 redef class ASignature
323 fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl])
324 do
325 for ap in n_params do
326 var reg = v.variable(ap.variable)
327 var orig_type = orig_sig[ap.position]
328 var apst = ap.variable.stype.as(not null)
329 if not orig_type < apst then
330 v.add_type_cast(params[ap.position], apst)
331 end
332 v.stmt(new IMove(reg, params[ap.position]))
333 end
334 for i in [0..n_closure_decls.length[ do
335 var wd = n_closure_decls[i]
336 v.closurevariables[wd.variable] = closdecls[i]
337 end
338 end
339 end
340
341 redef class AClosureDecl
342 redef fun accept_icode_generation(vv)
343 do
344 var v = vv.icode_ctx
345 var iclos = variable.closure.signature.generate_empty_iclosuredef(v)
346 var old_seq = v.seq
347 v.seq = iclos.body
348 escapable.continue_seq = iclos.body
349 escapable.continue_value = iclos.result
350 escapable.break_seq = v.return_seq
351 escapable.break_value = v.return_value
352 n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null)
353
354 if n_expr != null then
355 v.generate_stmt(n_expr)
356 v.iroutine.closure_decls[position].default = iclos
357
358 # Add a final break in case of break block witout value
359 if variable.closure.is_break and v.return_value == null then
360 v.stmt(new IEscape(v.return_seq.as(not null)))
361 end
362 end
363 v.seq = old_seq
364 end
365 end
366
367 redef class AConcreteMethPropdef
368 redef fun fill_iroutine(v, method)
369 do
370 var params = v.iroutine.params.to_a
371 var selfreg = v.variable(self_var)
372 v.stmt(new IMove(selfreg, params[0]))
373 params.shift
374
375 var orig_meth: MMLocalProperty = method.global.intro
376 var orig_sig = orig_meth.signature_for(method.signature.recv)
377 if n_signature != null then
378 n_signature.fill_iroutine_parameters(v, orig_sig, params, v.iroutine.closure_decls)
379 end
380
381 if self isa AConcreteInitPropdef then
382 v.invoke_super_init_calls_after(null)
383 end
384
385 if n_block != null then
386 v.generate_stmt(n_block)
387 end
388 end
389 end
390
391 redef class ADeferredMethPropdef
392 redef fun fill_iroutine(v, method)
393 do
394 v.add_abort("Deferred method called")
395 end
396 end
397
398 redef class AExternMethPropdef
399 redef fun fill_iroutine(v, method)
400 do
401 var params = v.iroutine.params
402 var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}"
403 if n_extern != null then
404 ename = n_extern.text
405 ename = ename.substring(1, ename.length-2)
406 end
407 var sig = method.signature
408 assert params.length == sig.arity + 1
409 var args = new Array[String]
410 args.add(sig.recv.unboxtype("@@@"))
411 for i in [0..sig.arity[ do
412 args.add(sig[i].unboxtype("@@@"))
413 end
414 var s = "{ename}({args.join(", ")})"
415 var rtype = sig.return_type
416 if rtype != null then
417 s = rtype.boxtype(s)
418 v.add_return_value(v.expr(new INative(s, params), rtype))
419 else
420 v.stmt(new INative(s, params))
421 end
422 end
423 end
424
425 redef class AInternMethPropdef
426 redef fun fill_iroutine(v, method)
427 do
428 var p = v.iroutine.params.to_a
429 var c = method.local_class.name
430 var n = method.name
431 var s: nullable String = null
432 if c == once "Int".to_symbol then
433 if n == once "object_id".to_symbol then
434 s = "@@@"
435 else if n == once "unary -".to_symbol then
436 s = "TAG_Int(-UNTAG_Int(@@@))"
437 else if n == once "output".to_symbol then
438 s = "printf(\"%ld\\n\", UNTAG_Int(@@@));"
439 else if n == once "ascii".to_symbol then
440 s = "TAG_Char(UNTAG_Int(@@@))"
441 else if n == once "succ".to_symbol then
442 s = "TAG_Int(UNTAG_Int(@@@)+1)"
443 else if n == once "prec".to_symbol then
444 s = "TAG_Int(UNTAG_Int(@@@)-1)"
445 else if n == once "to_f".to_symbol then
446 s = "BOX_Float((float)UNTAG_Int(@@@))"
447 else if n == once "+".to_symbol then
448 s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))"
449 else if n == once "-".to_symbol then
450 s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))"
451 else if n == once "*".to_symbol then
452 s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))"
453 else if n == once "/".to_symbol then
454 s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))"
455 else if n == once "%".to_symbol then
456 s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))"
457 else if n == once "<".to_symbol then
458 s = "TAG_Bool(UNTAG_Int(@@@)<UNTAG_Int(@@@))"
459 else if n == once ">".to_symbol then
460 s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))"
461 else if n == once "<=".to_symbol then
462 s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))"
463 else if n == once ">=".to_symbol then
464 s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))"
465 else if n == once "lshift".to_symbol then
466 s = "TAG_Int(UNTAG_Int(@@@)<<UNTAG_Int(@@@))"
467 else if n == once "rshift".to_symbol then
468 s = "TAG_Int(UNTAG_Int(@@@)>>UNTAG_Int(@@@))"
469 else if n == once "==".to_symbol then
470 s = "TAG_Bool((@@@)==(@@@))"
471 else if n == once "!=".to_symbol then
472 s = "TAG_Bool((@@@)!=(@@@))"
473 end
474 else if c == once "Float".to_symbol then
475 if n == once "object_id".to_symbol then
476 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
477 else if n == once "unary -".to_symbol then
478 s = "BOX_Float(-UNBOX_Float(@@@))"
479 else if n == once "output".to_symbol then
480 s = "printf(\"%f\\n\", UNBOX_Float(@@@));"
481 else if n == once "to_i".to_symbol then
482 s = "TAG_Int((bigint)UNBOX_Float(@@@))"
483 else if n == once "+".to_symbol then
484 s = "BOX_Float(UNBOX_Float(@@@)+UNBOX_Float(@@@))"
485 else if n == once "-".to_symbol then
486 s = "BOX_Float(UNBOX_Float(@@@)-UNBOX_Float(@@@))"
487 else if n == once "*".to_symbol then
488 s = "BOX_Float(UNBOX_Float(@@@)*UNBOX_Float(@@@))"
489 else if n == once "/".to_symbol then
490 s = "BOX_Float(UNBOX_Float(@@@)/UNBOX_Float(@@@))"
491 else if n == once "<".to_symbol then
492 s = "TAG_Bool(UNBOX_Float(@@@)<UNBOX_Float(@@@))"
493 else if n == once ">".to_symbol then
494 s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))"
495 else if n == once "<=".to_symbol then
496 s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))"
497 else if n == once ">=".to_symbol then
498 s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))"
499 end
500 else if c == once "Char".to_symbol then
501 if n == once "object_id".to_symbol then
502 s = "TAG_Int(UNTAG_Char(@@@))"
503 else if n == once "unary -".to_symbol then
504 s = "TAG_Char(-UNTAG_Char(@@@))"
505 else if n == once "output".to_symbol then
506 s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));"
507 else if n == once "ascii".to_symbol then
508 s = "TAG_Int((unsigned char)UNTAG_Char(@@@))"
509 else if n == once "succ".to_symbol then
510 s = "TAG_Char(UNTAG_Char(@@@)+1)"
511 else if n == once "prec".to_symbol then
512 s = "TAG_Char(UNTAG_Char(@@@)-1)"
513 else if n == once "to_i".to_symbol then
514 s = "TAG_Int(UNTAG_Char(@@@)-'0')"
515 else if n == once "+".to_symbol then
516 s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))"
517 else if n == once "-".to_symbol then
518 s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))"
519 else if n == once "*".to_symbol then
520 s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))"
521 else if n == once "/".to_symbol then
522 s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))"
523 else if n == once "%".to_symbol then
524 s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))"
525 else if n == once "<".to_symbol then
526 s = "TAG_Bool(UNTAG_Char(@@@)<UNTAG_Char(@@@))"
527 else if n == once ">".to_symbol then
528 s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))"
529 else if n == once "<=".to_symbol then
530 s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))"
531 else if n == once ">=".to_symbol then
532 s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))"
533 else if n == once "==".to_symbol then
534 s = "TAG_Bool((@@@)==(@@@))"
535 else if n == once "!=".to_symbol then
536 s = "TAG_Bool((@@@)!=(@@@))"
537 end
538 else if c == once "Bool".to_symbol then
539 if n == once "object_id".to_symbol then
540 s = "TAG_Int(UNTAG_Bool(@@@))"
541 else if n == once "unary -".to_symbol then
542 s = "TAG_Bool(-UNTAG_Bool(@@@))"
543 else if n == once "output".to_symbol then
544 s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");"
545 else if n == once "ascii".to_symbol then
546 s = "TAG_Bool(UNTAG_Bool(@@@))"
547 else if n == once "to_i".to_symbol then
548 s = "TAG_Int(UNTAG_Bool(@@@))"
549 else if n == once "==".to_symbol then
550 s = "TAG_Bool((@@@)==(@@@))"
551 else if n == once "!=".to_symbol then
552 s = "TAG_Bool((@@@)!=(@@@))"
553 end
554 else if c == once "NativeArray".to_symbol then
555 if n == once "object_id".to_symbol then
556 s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
557 else if n == once "[]".to_symbol then
558 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
559 else if n == once "[]=".to_symbol then
560 s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]=@@@"
561 else if n == once "copy_to".to_symbol then
562 var t = p[0]
563 p[0] = p[1]
564 p[1] = t
565 s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
566 end
567 else if c == once "NativeString".to_symbol then
568 if n == once "object_id".to_symbol then
569 s = "TAG_Int(UNBOX_NativeString(@@@))"
570 else if n == once "atoi".to_symbol then
571 s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))"
572 else if n == once "[]".to_symbol then
573 s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])"
574 else if n == once "[]=".to_symbol then
575 s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);"
576 else if n == once "copy_to".to_symbol then
577 var t = p[0]
578 p[0] = p[1]
579 p[1] = p[4]
580 p[4] = p[2]
581 p[2] = t
582 s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));"
583 end
584 else if n == once "object_id".to_symbol then
585 s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
586 else if n == once "sys".to_symbol then
587 s = "(G_sys)"
588 else if n == once "is_same_type".to_symbol then
589 s = "TAG_Bool((VAL2VFT(@@@)==VAL2VFT(@@@)))"
590 else if n == once "exit".to_symbol then
591 p[0] = p[1]
592 s = "exit(UNTAG_Int(@@@));"
593 else if n == once "calloc_array".to_symbol then
594 p[0] = p[1]
595 s = "NEW_NativeArray(UNTAG_Int(@@@), sizeof(val_t))"
596 else if n == once "calloc_string".to_symbol then
597 p[0] = p[1]
598 s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
599 end
600 if s == null then
601 v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
602 s = "NIT_NULL"
603 end
604 var rtype = method.signature.return_type
605 if rtype != null then
606 v.add_return_value(v.expr(new INative(s, p), rtype))
607 else
608 v.stmt(new INative(s, p))
609 end
610 end
611 end
612
613 ###############################################################################
614
615 redef class AExpr
616 redef fun accept_icode_generation(v) do end
617
618 # Generate icode sequence in the current A2IContext
619 # This method should not be called direclty: use generate_expr and generate_stmt from A2IContext instead
620 protected fun generate_icode(v: A2IContext): nullable IRegister is abstract
621 end
622
623 redef class AVardeclExpr
624 redef fun generate_icode(v)
625 do
626 var reg = v.variable(variable)
627 var ne = n_expr
628 if ne != null then
629 v.add_assignment(reg, v.generate_expr(ne))
630 end
631 return null
632 end
633 end
634
635 redef class ABlockExpr
636 redef fun generate_icode(v)
637 do
638 for ne in n_expr do v.generate_stmt(ne)
639 return null
640 end
641 end
642
643 redef class ADoExpr
644 redef fun generate_icode(v)
645 do
646 var seq_old = v.seq
647 var seq = new ISeq
648 v.stmt(seq)
649 escapable.break_seq = seq
650 v.seq = seq
651
652 v.generate_stmt(n_block)
653
654 v.seq = seq_old
655 return null
656 end
657 end
658
659 redef class AReturnExpr
660 redef fun generate_icode(v)
661 do
662 var ne = n_expr
663 if ne != null then
664 v.add_assignment(v.return_value.as(not null), v.generate_expr(ne))
665 end
666 v.stmt(new IEscape(v.return_seq.as(not null)))
667 return null
668 end
669 end
670
671 redef class ABreakExpr
672 redef fun generate_icode(v)
673 do
674 var ne = n_expr
675 if ne != null then
676 v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne))
677 end
678 v.stmt(new IEscape(escapable.break_seq.as(not null)))
679 return null
680 end
681 end
682
683 redef class AContinueExpr
684 redef fun generate_icode(v)
685 do
686 var ne = n_expr
687 if ne != null then
688 v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne))
689 end
690 v.stmt(new IEscape(escapable.continue_seq.as(not null)))
691 return null
692 end
693 end
694
695 redef class AAbortExpr
696 redef fun generate_icode(v)
697 do
698 v.add_abort("Aborted")
699 return null
700 end
701 end
702
703 redef class AIfExpr
704 redef fun generate_icode(v)
705 do
706 var iif = new IIf(v.generate_expr(n_expr))
707 v.stmt(iif)
708 var seq_old = v.seq
709
710 if n_then != null then
711 v.seq = iif.then_seq
712 v.generate_stmt(n_then)
713 end
714
715 if n_else != null then
716 v.seq = iif.else_seq
717 v.generate_stmt(n_else)
718 end
719
720 v.seq = seq_old
721 return null
722 end
723 end
724
725 redef class AWhileExpr
726 redef fun generate_icode(v)
727 do
728 var seq_old = v.seq
729 var iloop = new ILoop
730 v.stmt(iloop)
731 escapable.break_seq = iloop
732 v.seq = iloop
733
734 # Process condition
735 var iif = new IIf(v.generate_expr(n_expr))
736 v.stmt(iif)
737
738 # Process inside (condition is true)
739 if n_block != null then
740 v.seq = iif.then_seq
741 escapable.continue_seq = iif.then_seq
742 v.generate_stmt(n_block)
743 end
744
745 # Process escape (condition is false)
746 v.seq = iif.else_seq
747 v.stmt(new IEscape(iloop))
748
749 v.seq = seq_old
750 return null
751 end
752 end
753
754 redef class ALoopExpr
755 redef fun generate_icode(v)
756 do
757 var seq_old = v.seq
758 var iloop = new ILoop
759 v.stmt(iloop)
760 escapable.break_seq = iloop
761 v.seq = iloop
762
763 # Process inside
764 if n_block != null then
765 var seq = new ISeq
766 v.stmt(seq)
767 v.seq = seq
768 escapable.continue_seq = seq
769 v.generate_stmt(n_block)
770 end
771
772 v.seq = seq_old
773 return null
774 end
775 end
776
777 redef class AForExpr
778 redef fun generate_icode(v)
779 do
780 var expr_type = n_expr.stype
781
782 # Get iterator
783 var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol)
784
785 var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null)
786 var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type)
787
788 # Enter loop
789 var seq_old = v.seq
790 var iloop = new ILoop
791 v.stmt(iloop)
792 escapable.break_seq = iloop
793 v.seq = iloop
794
795 # Condition evaluation
796 var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol))
797 var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool)
798 var iif = new IIf(ireg_isok)
799
800 # Process insite the loop (condition is true)
801 v.stmt(iif)
802 v.seq = iif.then_seq
803 escapable.continue_seq = iif.then_seq
804
805 # Automatic variable assignment
806 var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol))
807 var va_stype = variable.stype.as(not null)
808 var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype)
809 var ireg_va = v.variable(variable)
810 v.add_assignment(ireg_va, ireg_item)
811
812 # Body evaluation
813 v.generate_stmt(n_block)
814
815 # Exit contition (condition is false)
816 v.seq = iif.else_seq
817 v.stmt(new IEscape(iloop))
818
819 # Next step
820 var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol))
821 v.seq = iloop
822 v.stmt(new ICall(meth_next, [ireg_iter]))
823
824 v.seq = seq_old
825 return null
826 end
827 end
828
829 redef class AAssertExpr
830 redef fun generate_icode(v)
831 do
832 var e = v.generate_expr(n_expr)
833 var iif = new IIf(e)
834 v.stmt(iif)
835 var seq_old = v.seq
836 v.seq = iif.else_seq
837 v.generate_stmt(n_else)
838 var id = n_id
839 if id == null then
840 v.add_abort("Assert failed")
841 else
842 v.add_abort("Assert %s failed", id.to_s)
843 end
844 v.seq = seq_old
845 return null
846 end
847 end
848
849 redef class AVarExpr
850 redef fun generate_icode(v)
851 do
852 return v.variable(variable)
853 end
854 end
855
856 redef class AVarAssignExpr
857 redef fun generate_icode(v)
858 do
859 var e = v.generate_expr(n_value)
860 v.add_assignment(v.variable(variable), e)
861 return null
862 end
863 end
864
865 redef class AVarReassignExpr
866 redef fun generate_icode(v)
867 do
868 var e1 = v.variable(variable)
869 var e2 = v.generate_expr(n_value)
870 var e3 = v.expr(new ICall(assign_method, [e1, e2]), assign_method.signature.return_type.as(not null))
871 v.add_assignment(e1, e3)
872 return null
873 end
874 end
875
876 redef class ASelfExpr
877 redef fun generate_icode(v)
878 do
879 return v.variable(variable)
880 end
881 end
882
883 redef class AIfexprExpr
884 redef fun generate_icode(v)
885 do
886 # Process condition
887 var iif = new IIf(v.generate_expr(n_expr))
888 v.stmt(iif)
889 var seq_old = v.seq
890
891 # Prepare result
892 var reg = v.new_register(stype)
893
894 # Process 'then'
895 v.seq = iif.then_seq
896 v.add_assignment(reg, v.generate_expr(n_then))
897
898 # Process 'else'
899 v.seq = iif.else_seq
900 v.add_assignment(reg, v.generate_expr(n_else))
901
902 v.seq = seq_old
903 return reg
904 end
905 end
906
907 redef class AEeExpr
908 redef fun generate_icode(v)
909 do
910 var e = v.generate_expr(n_expr)
911 var e2 = v.generate_expr(n_expr2)
912 return v.expr(new IIs(e, e2), stype)
913 end
914 end
915
916 redef class AOrExpr
917 redef fun generate_icode(v)
918 do
919 # Prepare result
920 var reg = v.new_register(stype)
921
922 # Process left operand (in a if/then)
923 var iif = new IIf(v.generate_expr(n_expr))
924 v.stmt(iif)
925 var seq_old = v.seq
926 v.seq = iif.then_seq
927 v.add_assignment(reg, v.lit_true_reg)
928
929 # Process right operand (in the else)
930 v.seq = iif.else_seq
931 v.add_assignment(reg, v.generate_expr(n_expr2))
932
933 v.seq = seq_old
934 return reg
935 end
936 end
937
938 redef class AAndExpr
939 redef fun generate_icode(v)
940 do
941 # Prepare result
942 var reg = v.new_register(stype)
943
944 # Process left operand (in a if/else)
945 var iif = new IIf(v.generate_expr(n_expr))
946 v.stmt(iif)
947 var seq_old = v.seq
948 v.seq = iif.else_seq
949 v.add_assignment(reg, v.lit_false_reg)
950
951 # Process right operand (in the then)
952 v.seq = iif.then_seq
953 v.add_assignment(reg, v.generate_expr(n_expr2))
954
955 v.seq = seq_old
956 return reg
957 end
958 end
959
960 redef class ANotExpr
961 redef fun generate_icode(v)
962 do
963 var e = v.generate_expr(n_expr)
964 return v.expr(new INot(e), stype)
965 end
966 end
967
968 redef class AIsaExpr
969 redef fun generate_icode(v)
970 do
971 var e = v.generate_expr(n_expr)
972 return v.expr(new ITypeCheck(e, n_type.stype), stype)
973 end
974 end
975
976 redef class AAsCastExpr
977 redef fun generate_icode(v)
978 do
979 var e = v.generate_expr(n_expr)
980 v.add_type_cast(e, stype)
981 return e
982 end
983 end
984
985 redef class AAsNotnullExpr
986 redef fun generate_icode(v)
987 do
988 var e = v.generate_expr(n_expr)
989 v.add_type_cast(e, stype)
990 return e
991 end
992 end
993
994 redef class ATrueExpr
995 redef fun generate_icode(v)
996 do
997 return v.lit_true_reg
998 end
999 end
1000
1001 redef class AFalseExpr
1002 redef fun generate_icode(v)
1003 do
1004 return v.lit_false_reg
1005 end
1006 end
1007
1008 redef class AIntExpr
1009 redef fun generate_icode(v)
1010 do
1011 return v.expr(new INative("TAG_Int({n_number.text})", null), stype)
1012 end
1013 end
1014
1015 redef class AFloatExpr
1016 redef fun generate_icode(v)
1017 do
1018 return v.expr(new INative("BOX_Float({n_float.text})", null), stype)
1019 end
1020 end
1021
1022 redef class ACharExpr
1023 redef fun generate_icode(v)
1024 do
1025 return v.expr(new INative("TAG_Char({n_char.text})", null), stype)
1026 end
1027 end
1028
1029 redef class AStringFormExpr
1030 redef fun generate_icode(v)
1031 do
1032 compute_string_infos
1033 var old_seq = v.seq
1034 var ionce = new IOnce
1035 var reg = v.expr(ionce, stype)
1036 v.seq = ionce.body
1037 var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring)
1038 var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int)
1039 var prop = v.visitor.get_method(stype, once "with_native".to_symbol)
1040 var e = v.expr(new INew(stype, prop, [ns, ni]), stype)
1041 v.add_assignment(reg, e)
1042 v.seq = old_seq
1043 return reg
1044 end
1045
1046 # The raw string value
1047 protected fun string_text: String is abstract
1048
1049 # The string in a C native format
1050 protected var _cstring: nullable String
1051
1052 # The string length in bytes
1053 protected var _cstring_length: nullable Int
1054
1055 # Compute _cstring and _cstring_length using string_text
1056 protected fun compute_string_infos
1057 do
1058 var len = 0
1059 var str = string_text
1060 var res = new Buffer
1061 var i = 0
1062 while i < str.length do
1063 var c = str[i]
1064 if c == '\\' then
1065 i = i + 1
1066 var c2 = str[i]
1067 if c2 != '{' and c2 != '}' then
1068 res.add(c)
1069 end
1070 c = c2
1071 end
1072 len = len + 1
1073 res.add(c)
1074 i = i + 1
1075 end
1076 _cstring = res.to_s
1077 _cstring_length = len
1078 end
1079 end
1080
1081 redef class AStringExpr
1082 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1083 end
1084 redef class AStartStringExpr
1085 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1086 end
1087 redef class AMidStringExpr
1088 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1089 end
1090 redef class AEndStringExpr
1091 redef fun string_text do return n_string.text.substring(1, n_string.text.length - 2)
1092 end
1093
1094 redef class ASuperstringExpr
1095 redef fun generate_icode(v)
1096 do
1097 var array = v.add_new_array(atype, n_exprs.length)
1098 var prop_to_s = v.visitor.get_method(v.visitor.type_object, once "to_s".to_symbol)
1099 for ne in n_exprs do
1100 var e = v.generate_expr(ne)
1101 if ne.stype != stype then
1102 e = v.expr(new ICall(prop_to_s, [e]), stype)
1103 end
1104 v.add_call_array_add(array, e)
1105 end
1106 return v.expr(new ICall(prop_to_s, [array]), stype)
1107 end
1108 end
1109
1110 redef class ANullExpr
1111 redef fun generate_icode(v)
1112 do
1113 return v.lit_null_reg
1114 end
1115 end
1116
1117 redef class AArrayExpr
1118 redef fun generate_icode(v)
1119 do
1120 var recv = v.add_new_array(stype, n_exprs.length)
1121 for ne in n_exprs do
1122 var e = v.generate_expr(ne)
1123 v.add_call_array_add(recv, e)
1124 end
1125 return recv
1126 end
1127 end
1128
1129 redef class ACrangeExpr
1130 redef fun generate_icode(v)
1131 do
1132 var e = v.generate_expr(n_expr)
1133 var e2 = v.generate_expr(n_expr2)
1134 var prop = v.visitor.get_method(stype, once "init".to_symbol)
1135 return v.expr(new INew(stype, prop, [e, e2]), stype)
1136 end
1137 end
1138
1139 redef class AOrangeExpr
1140 redef fun generate_icode(v)
1141 do
1142 var e = v.generate_expr(n_expr)
1143 var e2 = v.generate_expr(n_expr2)
1144 var prop = v.visitor.get_method(stype, once "without_last".to_symbol)
1145 return v.expr(new INew(stype, prop, [e, e2]), stype)
1146 end
1147 end
1148
1149 redef class ASuperExpr
1150 redef fun generate_icode(v)
1151 do
1152 var arity = v.iroutine.params.length - 1
1153 if init_in_superclass != null then
1154 arity = init_in_superclass.signature.arity
1155 end
1156 var args = new Array[IRegister].with_capacity(arity + 1)
1157 args.add(v.iroutine.params[0])
1158 if n_args.length != arity then
1159 for i in [0..arity[ do
1160 args.add(v.iroutine.params[i + 1])
1161 end
1162 else
1163 for na in n_args do
1164 args.add(v.generate_expr(na))
1165 end
1166 end
1167 var p = init_in_superclass
1168 if p != null then
1169 var rtype = p.signature.return_type
1170 if rtype != null then
1171 return v.expr(new ICall(p, args), rtype)
1172 else
1173 v.stmt(new ICall(p, args))
1174 return null
1175 end
1176 else
1177 p = prop
1178 var rtype = p.signature.return_type
1179 if rtype == null then
1180 v.stmt(new ISuper(p, args))
1181 return null
1182 else
1183 return v.expr(new ISuper(p, args), rtype)
1184 end
1185 end
1186 end
1187 end
1188
1189 redef class AAttrExpr
1190 redef fun generate_icode(v)
1191 do
1192 var e = v.generate_expr(n_expr)
1193 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1194 return v.add_attr_read(prop, e)
1195 end
1196 end
1197
1198 redef class AAttrAssignExpr
1199 redef fun generate_icode(v)
1200 do
1201 var e = v.generate_expr(n_expr)
1202 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1203 var e2 = v.generate_expr(n_value)
1204 v.stmt(new IAttrWrite(prop, e, e2))
1205 return null
1206 end
1207 end
1208 redef class AAttrReassignExpr
1209 redef fun generate_icode(v)
1210 do
1211 var e1 = v.generate_expr(n_expr)
1212 if n_expr.stype.is_nullable then v.add_null_reciever_check(e1)
1213 var e2 = v.expr(new IAttrRead(prop, e1), attr_type)
1214 var e3 = v.generate_expr(n_value)
1215 var e4 = v.expr(new ICall(assign_method, [e2, e3]), attr_type)
1216 v.stmt(new IAttrWrite(prop, e1, e4))
1217 return null
1218 end
1219 end
1220
1221 redef class AIssetAttrExpr
1222 redef fun generate_icode(v)
1223 do
1224 var e = v.generate_expr(n_expr)
1225 if n_expr.stype.is_nullable then v.add_null_reciever_check(e)
1226 return v.expr(new IAttrIsset(prop, e), stype)
1227 end
1228 end
1229
1230 redef class AAbsAbsSendExpr
1231 # Compile each argument and add them to the array
1232 fun generate_icode_for_arguments_in(v: A2IContext, args: Array[IRegister], signature: MMSignature)
1233 do
1234 var par_arity = signature.arity
1235 var par_vararg = signature.vararg_rank
1236 var raw_args = raw_arguments
1237 var raw_arity = raw_args.length
1238 var arg_idx = 0
1239 for par_idx in [0..par_arity[ do
1240 var a: AExpr
1241 var par_type = signature[par_idx]
1242 if par_idx == par_vararg then
1243 var arr = v.add_new_array(v.visitor.type_array(par_type), raw_arity-par_arity)
1244 for i in [0..(raw_arity-par_arity)] do
1245 a = raw_args[arg_idx]
1246 v.add_call_array_add(arr, v.generate_expr(a))
1247 arg_idx = arg_idx + 1
1248 end
1249 args.add(arr)
1250 else
1251 a = raw_args[arg_idx]
1252 args.add(v.generate_expr(a))
1253 arg_idx = arg_idx + 1
1254 end
1255 end
1256 end
1257 end
1258
1259 redef class ASendExpr
1260 redef fun generate_icode(v)
1261 do
1262 var recv = v.generate_expr(n_expr)
1263 var args = new Array[IRegister]
1264 args.add(recv)
1265 var prop = prop
1266 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1267 var r: nullable IRegister = null # The full result of the send (raw call + breaks)
1268 var r2: nullable IRegister # The raw result of the call
1269
1270 # Prepare closures
1271 var seq_old = v.seq
1272 var closcns: nullable Array[nullable IClosureDef] = null
1273 if not prop_signature.closures.is_empty then
1274 var rtype = prop_signature.return_type
1275 if rtype != null then
1276 r = v.new_register(rtype)
1277 end
1278 var seq = new ISeq
1279 v.stmt(seq)
1280 v.seq = seq
1281 closcns = new Array[nullable IClosureDef]
1282 var cdarity = 0
1283 if closure_defs != null then cdarity = closure_defs.length
1284 var closure_defs = closure_defs
1285 for mmc in prop_signature.closures do
1286 var found = false
1287 var name = mmc.name
1288 if closure_defs != null then
1289 for cd in closure_defs do
1290 if cd.n_id.to_symbol != name then continue
1291 assert found == false
1292 found = true
1293 cd.escapable.break_seq = seq
1294 cd.escapable.break_value = r
1295 var cn = cd.generate_iclosuredef(v)
1296 closcns.add(cn)
1297 end
1298 end
1299 if not found then
1300 closcns.add(null)
1301 end
1302 end
1303 end
1304
1305 r2 = v.add_call(prop, args, closcns)
1306
1307 # Closure work
1308 if not prop_signature.closures.is_empty then
1309 if r != null and r2 != null then v.add_assignment(r, r2)
1310 v.seq = seq_old
1311 else
1312 r = r2
1313 end
1314
1315 if prop.global.is_init then
1316 v.invoke_super_init_calls_after(prop)
1317 end
1318 return r
1319 end
1320 end
1321
1322 redef class ASendReassignExpr
1323 redef fun generate_icode(v)
1324 do
1325 var recv = v.generate_expr(n_expr)
1326 if n_expr.stype.is_nullable then v.add_null_reciever_check(recv)
1327 var args = new Array[IRegister]
1328 args.add(recv)
1329 generate_icode_for_arguments_in(v, args, read_prop.signature.as(not null))
1330
1331 var e2 = v.expr(new ICall(read_prop, args), read_prop.signature.return_type.as(not null))
1332 var e3 = v.generate_expr(n_value)
1333 var e4 = v.expr(new ICall(assign_method, [e2, e3]), assign_method.signature.return_type.as(not null))
1334 var args2 = args.to_a
1335 args2.add(e4)
1336 v.stmt(new ICall(prop, args2))
1337 return null
1338 end
1339 end
1340
1341 redef class ANewExpr
1342 redef fun generate_icode(v)
1343 do
1344 var args = new Array[IRegister]
1345 generate_icode_for_arguments_in(v, args, prop.signature.as(not null))
1346 return v.expr(new INew(stype, prop, args), stype)
1347 end
1348 end
1349
1350 redef class AProxyExpr
1351 redef fun generate_icode(v)
1352 do
1353 return v.generate_expr(n_expr)
1354 end
1355 end
1356
1357 redef class AOnceExpr
1358 redef fun generate_icode(v)
1359 do
1360 var ionce = new IOnce
1361 var reg = v.expr(ionce, stype)
1362 var old_seq = v.seq
1363 v.seq = ionce.body
1364
1365 var e = v.generate_expr(n_expr)
1366 v.add_assignment(reg, e)
1367
1368 v.seq = old_seq
1369 return reg
1370 end
1371 end
1372
1373
1374 redef class AClosureDef
1375 var _iclosure_def: nullable IClosureDef
1376
1377 fun generate_iclosuredef(v: A2IContext): IClosureDef
1378 do
1379 # Prepare signature
1380 var args = new Array[IRegister]
1381 var sig = closure.signature
1382 for i in [0..sig.arity[ do
1383 args.add(v.new_register(sig[i]))
1384 end
1385 var ret: nullable IRegister = null
1386 var rtype = sig.return_type
1387 if rtype != null then
1388 ret = v.new_register(rtype)
1389 end
1390
1391 var iclos = new IClosureDef(args, ret)
1392 iclos.location = location
1393
1394 # Prepare env
1395 var seq_old = v.seq
1396 v.seq = iclos.body
1397 escapable.continue_seq = iclos.body
1398 escapable.continue_value = iclos.result
1399
1400 # Assign parameters
1401 for i in [0..variables.length[ do
1402 var res = v.variable(variables[i])
1403 v.add_assignment(res, iclos.params[i])
1404 end
1405
1406 v.generate_stmt(n_expr)
1407
1408 # Add a final break in case of break block witout value
1409 if closure.is_break and escapable.break_value == null then
1410 v.stmt(new IEscape(escapable.break_seq.as(not null)))
1411 end
1412
1413 v.seq = seq_old
1414 _iclosure_def = iclos
1415 return iclos
1416 end
1417 end
1418
1419 redef class AClosureCallExpr
1420 redef fun generate_icode(v)
1421 do
1422 # Geneate arguments
1423 var args = new Array[IRegister]
1424 generate_icode_for_arguments_in(v, args, variable.closure.signature)
1425
1426 # Prepare icall
1427 var closdecl = v.closurevariables[variable]
1428 var icall = new IClosCall(closdecl, args)
1429 var seq_old = v.seq
1430
1431 # Fill break of ical
1432 if n_closure_defs.length == 1 then do
1433 var iseq = new ISeq
1434 icall.break_seq = iseq
1435 v.seq = iseq
1436 v.generate_stmt(n_closure_defs.first.n_expr)
1437 v.seq = seq_old
1438 end
1439
1440 # Prepare in case of default block
1441 var iif: nullable IIf = null # The iif of default block
1442 var closdecl_default = closdecl.default # The default (if any)
1443 if closdecl_default != null then
1444 iif = new IIf(v.expr(new IHasClos(closdecl), v.visitor.type_bool))
1445 v.stmt(iif)
1446 v.seq = iif.then_seq
1447 end
1448
1449 # Add the icall
1450 var r2: nullable IRegister = null # the result of the icall
1451 var rtype = variable.closure.signature.return_type
1452 if rtype == null then
1453 v.stmt(icall)
1454 else
1455 r2 = v.expr(icall, rtype)
1456 end
1457
1458 # Process the case of default block
1459 var r: nullable IRegister = null # the real result
1460 if closdecl_default != null then
1461 assert iif != null
1462 if r2 != null then
1463 assert rtype != null
1464 r = v.new_register(rtype)
1465 v.add_assignment(r, r2)
1466 end
1467 v.seq = iif.else_seq
1468 var r3 = v.inline_routine(closdecl_default, args, null)
1469 if r != null then
1470 assert r3 != null
1471 v.add_assignment(r, r3)
1472 end
1473 v.seq = seq_old
1474 else
1475 r = r2
1476 end
1477 return r
1478 end
1479 end