1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2009 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Help generation of icode
22 # Helps to generate icodes in a iroutine
24 # Add a new statment in the current icode sequence
25 # Can be used with expression if the result is ignored of if the result is already set
28 s
.location
= _current_location
32 # Add a new expression in the current icode sequence and return a new associated result register
33 fun expr
(e
: ICode, s
: MMType): IRegister
36 assert e
.result
== null
37 var reg
= new_register
(s
)
42 # Add an assignement (IMove) in the current icode sequence
43 fun add_assignment
(reg
: IRegister, v
: IRegister)
45 stmt
(new IMove(reg
, v
))
48 # Check that the reciever e is not null (IIs + IAbort)
49 fun add_null_reciever_check
(e
: IRegister)
51 var nul
= lit_null_reg
52 var c
= expr
(new IIs(e
, nul
), module.type_bool
)
57 add_abort
("Reciever is null")
61 # Add a type cast (ITypeCheck + IAbort) in the current icode sequence
62 fun add_type_cast
(e
: IRegister, stype
: MMType)
64 var c
= expr
(new ITypeCheck(e
, stype
), module.type_bool
)
69 add_abort
("Cast failed")
73 # Add an attr check (IAttrIsset + IAbort) in the current icode sequence
74 fun add_attr_check
(prop
: MMAttribute, e
: IRegister)
76 if not prop
.signature
.return_type
.is_nullable
then
77 var cond
= expr
(new IAttrIsset(prop
, e
), module.type_bool
)
78 var iif
= new IIf(cond
)
82 add_abort
("Uninitialized attribute %s", prop
.name
.to_s
)
87 # Add an IAttrRead guarded by an add_attr_check in the current icode sequence
88 fun add_attr_read
(prop
: MMAttribute, e
: IRegister): IRegister
90 add_attr_check
(prop
, e
)
91 return expr
(new IAttrRead(prop
, e
), prop
.signature
.return_type
.as(not null))
94 # Add a localized IAbort
95 fun add_abort
(s
: String...)
97 stmt
(new IAbort(s
, module))
100 # Add an assigment to the iroutine return value
101 # Beware, no jump is generated
102 fun add_return_value
(reg
: IRegister)
104 add_assignment
(iroutine
.result
.as(not null), reg
)
107 # Add an ICall with possible simple inlining in the current icode sequence
108 fun add_call
(prop
: MMMethod, args
: Array[IRegister], closcns
: nullable Array[nullable IClosureDef]): nullable IRegister
110 var ee
= once
"==".to_symbol
112 # Inline "x!=y" as "not x==y"
113 var ne
= once
"!=".to_symbol
114 if prop
.name
== ne
then
115 var eqp
= prop
.signature
.recv
.local_class
.select_method
(ee
)
116 var eqcall
= add_call
(eqp
, args
, closcns
).as(not null)
117 return expr
(new INot(eqcall
), module.type_bool
)
120 # TODO: Inline x==y as "x is y or (x != null and (== is not the Object one) and x.==(y))"
121 # inline "x==y" as "x is y or x != null and x.==(y)"
122 var icall
= new ICall(prop
, args
)
123 icall
.closure_defs
= closcns
124 if prop
.name
== ee
then
126 var reg
= new_register
(module.type_bool
)
128 var cond
= expr
(new IIs(args
[0], args
[1]), module.type_bool
)
129 var iif
= new IIf(cond
)
133 add_assignment
(reg
, cond
)
136 # Do the "x != null" part iff x is nullable
137 if args
[0].stype
.is_nullable
then
138 var nul
= lit_null_reg
139 cond
= expr
(new IIs(args
[0], nul
), module.type_bool
)
143 add_assignment
(reg
, lit_false_reg
)
147 add_assignment
(reg
, expr
(icall
, module.type_bool
))
152 if args
.first
.stype
.is_nullable
then add_null_reciever_check
(args
.first
)
153 var rtype
= prop
.signature
.return_type
154 if rtype
!= null then
155 return expr
(icall
, rtype
)
162 # Return a literal "null" value
163 fun lit_null_reg
: IRegister
165 return new_register
(module.type_none
)
168 # Return a literal "true" value
169 fun lit_true_reg
: IRegister
171 var e
= new INative("TAG_Bool(true)", null)
173 return expr
(e
, module.type_bool
)
176 # Return a literal "false" value
177 fun lit_false_reg
: IRegister
179 var e
= new INative("TAG_Bool(false)", null)
181 return expr
(e
, module.type_bool
)
185 fun new_register
(s
: MMType): IRegister
187 return new IRegister(s
)
190 # The module where classes and types are extracted
191 readable var _module
: MMModule
193 # The current iroutine build
194 readable var _iroutine
: IRoutine
196 # The current sequence of icodes
197 readable writable var _seq
: ISeq
199 init(module: MMModule, r
: IRoutine)
202 _current_location
= r
.location
207 # New ICodes are set to this location
208 readable writable var _current_location
: nullable Location = null
211 redef class MMSignature
212 # Create an empty IRoutine that match the signature
213 fun generate_empty_iroutine
: IRoutine
215 var args
= new Array[IRegister]
216 args
.add
(new IRegister(recv
)) # Self
217 for i
in [0..arity
[ do
218 args
.add
(new IRegister(self[i
]))
220 var res
: nullable IRegister = null
221 var rtype
= return_type
222 if rtype
!= null then
223 res
= new IRegister(rtype
)
225 var iroutine
= new IRoutine(args
, res
)
226 var clos
: nullable Array[IClosureDecl] = null
227 if not closures
.is_empty
then
228 clos
= new Array[IClosureDecl]
230 clos
.add
(new IClosureDecl(c
))
232 iroutine
.closure_decls
= clos
237 # Create an empty IClosureDef that match the signature
238 fun generate_empty_iclosuredef
: IClosureDef
240 var args
= new Array[IRegister]
241 for i
in [0..arity
[ do
242 args
.add
(new IRegister(self[i
]))
244 var res
: nullable IRegister = null
245 var rtype
= return_type
246 if rtype
!= null then
247 res
= new IRegister(rtype
)
249 var iroutine
= new IClosureDef(args
, res
)
250 var clos
: nullable Array[IClosureDecl] = null
251 if not closures
.is_empty
then
252 clos
= new Array[IClosureDecl]
254 clos
.add
(new IClosureDecl(c
))
256 iroutine
.closure_decls
= clos