1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2011 Alexis Laferrière <alexis.laf@xymus.net>
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 # Information and tools relevant to the frontier files
25 redef class MMSrcModule
26 fun compile_frontier
( v
: FrontierVisitor )
28 # assumes is extern hybrid (verified by caller)
30 v
.body
.add
( "#include \"{name}._nitni
.h\
"\n" )
33 v
.header_top
.add
( "#include <nit_common.h>\n" )
34 v
.header_top
.add
( "#include \"{v.cprogram.module_header_name(self)}\
"\n" )
36 var guard_name
= "{name.to_s.to_upper}_NITNI_H"
37 v
.header_top
.add
( "#ifndef {guard_name}\n" )
38 v
.header_top
.add
( "#define {guard_name}\n\n" )
40 # import custom _nit.h file from frontier
41 var native_header
= "{directory.path}/{name}.nit.h"
42 if not native_header
.file_exists
then # try old style
43 native_header
= "{directory.path}/{name}_nit.h"
45 if native_header
.file_exists
then
46 v
.body
.add
( "#include \"{native_header.path_from_parent}\
"\n" )
47 v
.header
.add
( "#include \"{native_header.path_from_parent}\
"\n" )
50 for local_class
in local_classes
do
52 for prop
in local_class
.local_local_properties
do
53 # if defined of redefined in this module
55 if prop
.mmmodule
== self and
56 prop
isa MMSrcMethod and prop
.is_extern
then
57 prop
.compile_extern_to_frontier
( v
)
62 # if class is extern and defined here first
63 if local_class
.global
.intro
== local_class
and
64 local_class
.global
.is_extern
then
65 local_class
.compile_defaut_extern_type
( v
)
69 v
.header
.add
( "#endif\n" )
73 redef class MMSrcMethod
74 fun compile_extern_to_frontier
( v
: FrontierVisitor )
76 # defines types used in signature
77 if signature
!= null then
78 signature
.compile_frontier
( v
)
81 for imported
in explicit_imports
do
82 # adds friendly access to property
83 v
.friendlys
.add
( imported
)
85 # defines relevant types
86 imported
.signature
.compile_frontier
( v
)
89 # adds casts and as verifications
90 for cast
in explicit_casts
do
93 v
.types
.add
( cast
.from
)
94 v
.types
.add
( cast
.to
)
99 compile_super_to_frontier
( v
)
102 # adds function in frontier to be called by pure nit
103 compile_out_to_frontier
( v
)
106 # Compiles body and header for the friendly super method.
107 # The friendly super method is called by custom native code and
108 # calls the generated C code to execute the real implementation.
109 # It handles types conversion and verifications.
110 fun compile_super_to_frontier
( v
: FrontierVisitor )
113 v
.header
.add
( "\n/* friendly for super of {full_name} */\n" )
114 v
.header
.add
( "{frontier_super_csignature_from( mmmodule )};\n" )
116 # Defines a local name for simplier use, as with friendlys.
117 v
.header
.add
( "#ifndef {friendly_super_cname}\n" )
118 v
.header
.add
( "#define {friendly_super_cname} {local_friendly_super_name_from( mmmodule )}\n" )
119 v
.header
.add
( "#endif\n" )
122 v
.body
.add
( "\n/* friendly for super of {full_name} */\n" )
123 var fc
= new FunctionCompiler( friendly_super_csignature
)
126 var params
= new Array[String]
129 var name_for_sub
= "recv___nit"
130 fc
.decls
.add
( "val_t {name_for_sub};\n" )
131 fc
.exprs
.add
( "{signature.recv.assign_from_friendly( name_for_sub, "recv" )};\n" )
132 params
.add
( name_for_sub
)
135 for p
in signature
.params
do
136 name_for_sub
= "{p.name}___nit"
137 fc
.decls
.add
( "val_t {name_for_sub};\n" )
138 fc
.exprs
.add
( "{p.mmtype.assign_from_friendly( name_for_sub, p.name.to_s )};\n" )
139 params
.add
( name_for_sub
)
142 # hook to generated C
143 var return_type
: nullable MMType = null
145 if signature
.return_type
!= null then
146 return_type
= signature
.return_type
150 if return_type
!= null then
151 fc
.decls
.add
( "{return_type.friendly_extern_name} return___nitni;\n" )
152 fc
.decls
.add
( "val_t return___nit;\n" )
153 s
.append
( "return___nit = " )
156 s
.append
( "{super_meth_call}( recv___nit )" )
158 s
.append
( "( {params.join( ", " )} );\n" )
160 fc
.exprs
.add
( s
.to_s
)
163 if return_type
!= null
165 fc
.exprs
.add
( "{return_type.assign_to_friendly( "return___nitni", "return___nit" )};\n" )
166 fc
.exprs
.add
( "return return___nitni;\n" )
169 v
.body
.append
( fc
.to_writer
)
172 # Compiles body and header for the out method.
173 # The out method is called by generated C code
174 # It handles variables conversions and verification
175 fun compile_out_to_frontier
( v
: FrontierVisitor )
178 v
.header
.add
( "\n/* out/indirect function for {full_name} */\n" )
179 v
.header
.add
( "{out_csignature};\n" ) # incoming types boxed
182 v
.body
.add
( "/* out/indirect function for {full_name} */\n" )
183 var fc
= new FunctionCompiler( out_csignature
)
186 var params
= new List[String]
189 var name_for_impl
= "recv___nitni"
190 fc
.decls
.add
( "{signature.recv.friendly_extern_name} {name_for_impl};\n" )
191 fc
.exprs
.add
( "{signature.recv.assign_to_friendly( name_for_impl, "recv" )};\n" )
192 params
.add
( name_for_impl
)
195 for p
in signature
.params
do
196 var name_for_impl
= "{p.name}___nitni"
197 fc
.decls
.add
( "{p.mmtype.friendly_extern_name} {name_for_impl};\n" )
198 fc
.exprs
.add
( "{p.mmtype.assign_to_friendly( name_for_impl, p.name.to_s )};\n" )
199 params
.add
( name_for_impl
)
203 var return_type
: nullable MMType = null
205 if signature
.return_type
!= null then
206 return_type
= signature
.return_type
208 return_type
= local_class
.get_type
212 if return_type
!= null then
213 fc
.decls
.add
( "{return_type.friendly_extern_name} return___nitni;\n" )
214 fc
.decls
.add
( "val_t return___nit;\n" )
215 s
.append
( "return___nitni = " )
218 s
.append
( "{extern_name.as(not null)}( {params.join( ", " )} );\n" )
220 fc
.exprs
.add
( s
.to_s
)
223 if return_type
!= null then
224 fc
.exprs
.add
( "{return_type.assign_from_friendly( "return___nit", "return___nitni" )};\n" )
225 fc
.exprs
.add
( "return return___nit;\n" )
228 v
.body
.append
( fc
.to_writer
)
233 redef class MMLocalClass
234 # Defines a defaut type for special of pointers in frontier.
235 # Can be overriden in the custime .nit.h file, as seen with nits.
236 fun compile_defaut_extern_type
( v
: FrontierVisitor )
238 v
.header
.add
( "#ifndef {get_type.friendly_extern_name}\n" )
239 v
.header
.add
( "\ttypedef void* {get_type.friendly_extern_name};\n" )
240 v
.header
.add
( "#endif\n\n" )
244 redef class MMSignature
245 fun compile_frontier
( v
: FrontierVisitor )
251 for p
in params
do v
.types
.add
( p
.mmtype
)
261 class FrontierVisitor
262 # frontier file header
264 # header comments, imports, guard and types
265 var header_top
: Writer = new Writer
268 var header
: Writer = new Writer
271 var body
: Writer = new Writer
273 # set of imported functions, cached to avoid repetitions
274 var friendlys
: Set[ MMExplicitImport ] = new HashSet[ MMExplicitImport ]
276 # set of relevant types, cached to avoid repetitions
277 var types
: Set[ MMType ] = new HashSet[ MMType ]
279 # set of imported casts and as, cached to avoid repetitions
280 var casts
: Set[ MMImportedCast ] = new HashSet[ MMImportedCast ]
282 var mmmodule
: MMModule
284 var cprogram
: CProgram
289 for t
in types
do t
.compile_to_frontier
( self )
292 for friendly
in friendlys
do friendly
.compile_friendly_to_frontier
( self )
295 for cast
in casts
do cast
.compile_to_frontier
( self )
298 fun write_to_files
( base_path
: String )
300 var path
= "{base_path}._nitni.h"
301 var stream
= new OFStream.open
( path
)
302 header_top
.write_to_stream
( stream
)
303 header
.write_to_stream
( stream
)
306 path
= "{base_path}._nitni.c"
307 stream
= new OFStream.open
( path
)
308 body
.write_to_stream
( stream
)
314 # return path from one level deeper
315 # could be moved to stdlib.file
316 fun path_from_parent
: String
318 if self[0] == '/' # is_absolute
328 redef class MMImportedCast
329 # Defines functions to cast types and verify the type of an object.
330 fun compile_to_frontier
( v
: FrontierVisitor )
333 if not ( is_about_nullable_only
and is_not_null_to_nullable
) then
334 v
.header
.add
( "\n/* Type check for {from} with {to} */\n" )
335 v
.header
.add
( "{is_a_local_csignature( v.mmmodule )};\n" )
337 v
.header
.add
( "#ifndef {is_a_friendly_extern_name}\n" )
338 v
.header
.add
( "#define {is_a_friendly_extern_name} {is_a_local_cname( v.mmmodule )}\n" )
339 v
.header
.add
( "#endif\n" )
341 var fc
= compile_is
( v
.mmmodule
)
342 v
.body
.append
( fc
.to_writer
)
345 # compile cast itself
346 v
.header
.add
( "\n/* Cast for {from} to {to} */\n" )
347 v
.header
.add
( "{as_local_csignature( v.mmmodule )};\n" )
349 v
.header
.add
( "#ifndef {as_friendly_extern_name}\n" )
350 v
.header
.add
( "#define {as_friendly_extern_name} {as_local_cname( v.mmmodule )}\n" )
351 v
.header
.add
( "#endif\n" )
353 var fc
= compile_as
( v
.mmmodule
)
354 v
.body
.append
( fc
.to_writer
)
357 # Compiles a function to cast an object to a different type.
358 # Verify type and if it is null.
359 fun compile_as
( m
: MMModule ) : FunctionCompiler
361 var fc
= new FunctionCompiler( as_local_csignature
( m
) )
364 var temp_name
= "temp"
366 fc
.decls
.add
( "val_t {temp_name};\n" )
367 fc
.decls
.add
( "{to.friendly_extern_name} {out_name};\n" )
369 fc
.exprs
.add
( "{from.assign_from_friendly(temp_name, in_name)};\n" )
371 # makes sur it is not null if it cannot be
372 if not to
.is_nullable
then
373 compile_check_is_not_null
( fc
, temp_name
)
376 # makes sure it's the right type, unless it's only a cast about null
377 if not is_about_nullable_only
then # inter types
378 to
.compile_check_isa
( fc
, temp_name
)
381 fc
.exprs
.add
( "{to.assign_to_friendly(out_name, temp_name)};\n" )
383 fc
.exprs
.add
( "return {out_name};\n" )
388 # Compiles a function to verify if an object is of the given type.
389 # Verify type and if it is null.
390 fun compile_is
( m
: MMModule ) : FunctionCompiler
392 var fc
= new FunctionCompiler( is_a_local_csignature
( m
) )
394 var temp_name
= "temp"
395 fc
.decls
.add
( "val_t {temp_name};\n" )
397 fc
.exprs
.add
( "{from.assign_from_friendly(temp_name, in_name)};\n" )
399 if is_nullable_to_not_null
then # from null
400 if is_about_nullable_only
then # opposite, we want to know if null
401 fc
.exprs
.add
( "if ( ! ISNULL({temp_name}) ) return 0;\n" )
403 fc
.exprs
.add
( "if ( ISNULL({temp_name}) ) return 0;\n" )
407 if not is_about_nullable_only
then # inter types
408 fc
.exprs
.add
( "if ( ! {to.compile_condition_isa( temp_name )} ) return 0;\n" )
411 fc
.exprs
.add
( "return 1;\n" )
416 # Compiles lines of code to check if an object is not null.
417 # Is to be nested within another function.
418 fun compile_check_is_not_null
( fc
: FunctionCompiler, name
: String )
420 fc
.exprs
.add
( "if ( ISNULL({name}) )\{" )
421 fc
.exprs
.add
( "\tfprintf( stderr, \"Casting from
{from} to
{to} failed because value
is null.\
" );\n" )
422 fc
.exprs
.add
( "\tabort();\n" )
426 redef fun ==( other
)
428 return other
isa MMImportedCast and
429 other
.from
== from
and other
.to
== to
433 return from
.hash
+ to
.hash
438 # Compiles a lines of code to ensure that an object is of the given type.
439 # Aborts when it is of the wrong type
440 # Does not check if it is null.
441 # Is to be nested within another function.
442 fun compile_check_isa
( fc
: FunctionCompiler, name
: String )
444 fc
.exprs
.add
( "if ( ! {compile_condition_isa( name )} )\{" )
445 fc
.exprs
.add
( "\tfprintf( stderr, \"Casting to
{self} failed because value
is not a
{self}.\
" );\n" )
446 fc
.exprs
.add
( "\tabort();\n" )
450 # Compiles an expression to verify if an object is of the given type.
451 # To be nested within a condition.
452 fun compile_condition_isa
( var_name
: String ) : String
454 return "( ISOBJ( {var_name} ) ? OBJISA( {var_name}, {local_class.cname} ): VALISA( {var_name}, {local_class.cname} ) )"
457 # Defines a friendly type in C for a given Nit type.
458 # Standard Nit classes are kept within a struct.
459 fun compile_to_frontier
( v
: FrontierVisitor )
461 var pi
= local_class
.primitive_info
462 if pi
== null or is_nullable
then
463 var name
= friendly_extern_name
464 var guard
= "{name.to_s.to_upper}_TYPE"
467 v
.header_top
.add
( "#ifndef {guard}\n" )
468 v
.header_top
.add
( "#define {guard}\n" )
469 v
.header_top
.add
( "typedef struct s_{name}\{\n" )
470 v
.header_top
.add
( "\tval_t v;\n" )
471 v
.header_top
.add
( "\} {name};\n" )
472 v
.header_top
.add
( "#endif\n\n" )
474 # add null version, as a struct
476 var null_getter
= "null_{as_notnull.friendly_extern_name}"
477 var null_getter_local
= "{mmmodule.to_s}_{null_getter}"
479 v
.header
.add
( "{name} {null_getter_local}();\n" )
481 v
.header
.add
( "#ifndef {null_getter}\n" )
482 v
.header
.add
( "#define {null_getter} {null_getter_local}\n" )
483 v
.header
.add
( "#endif\n\n" )
485 v
.body
.add
( "{name} {null_getter_local}()\n" )
487 v
.body
.add
( "\t{name} n;\n" )
488 v
.body
.add
( "\tn.v = NIT_NULL;\n" )
489 v
.body
.add
( "\treturn n;\n" )
490 v
.body
.add
( "\}\n\n" )
496 redef class MMExplicitImport
497 fun compile_friendly_to_frontier
( v
: FrontierVisitor )
499 # prototype in header
500 v
.header
.add
( "/* friendly for {method.full_name} */\n" )
501 v
.header
.add
( "{method.frontier_csignature_from( v.mmmodule, local_class )};\n" )
503 # Defines a simplier name to be used within this module and to prevent
504 # conflict with other modules importing the same friendly.
505 v
.header
.add
( "#ifndef {method.friendly_extern_name( local_class )}\n" )
506 v
.header
.add
( "#define {method.friendly_extern_name( local_class )} {method.local_friendly_name_from( v.mmmodule, local_class )}\n" )
507 v
.header
.add
( "#endif\n" )
509 # implementation in body
510 v
.body
.add
( "/* friendly for {method.full_name} */\n" )
512 var fc
= new FunctionCompiler( method
.frontier_csignature_from
( v
.mmmodule
, local_class
) )
515 var params
= new Array[String]
517 # if not init, add receiver
518 if not method
.is_init
then
519 var name_for_sub
= "recv___nit"
520 fc
.decls
.add
( "val_t {name_for_sub};\n" )
521 fc
.exprs
.add
( "{signature.recv.assign_from_friendly( name_for_sub, "recv" )};\n" )
522 params
.add
( name_for_sub
)
525 for p
in signature
.params
do
526 var name_for_sub
= "{p.name}___nit"
527 fc
.decls
.add
( "val_t {name_for_sub};\n" )
528 fc
.exprs
.add
( "{p.mmtype.assign_from_friendly( name_for_sub, p.name.to_s )};\n" )
529 params
.add
( name_for_sub
)
533 var return_type
: nullable MMType = null
535 # handles return of method or constructor
536 if method
.signature
.return_type
!= null then
537 return_type
= method
.signature
.return_type
538 else if method
.is_init
then
539 return_type
= method
.local_class
.get_type
543 if return_type
!= null then
544 fc
.decls
.add
( "{return_type.friendly_extern_name} result___nitni;\n" )
545 fc
.decls
.add
( "val_t result___nit;\n" )
546 s
.append
( "result___nit = " )
549 # hook to generated C code
550 if method
.is_init
then
551 s
.append
( "NEW_{local_class}_{method.global.intro.cname}" )
553 s
.append
( "{method.global.meth_call}( recv___nit )" )
556 s
.append
( "( {params.join( ", " )} );\n" )
558 fc
.exprs
.add
( s
.to_s
)
561 if return_type
!= null then
562 var result_name_nitni
= "result___nitni"
563 var result_name_nit
= "result___nit"
565 fc
.exprs
.add
( "{return_type.assign_to_friendly( result_name_nitni, result_name_nit )};\n" )
566 fc
.exprs
.add
( "return {result_name_nitni};\n" )
569 v
.body
.append
( fc
.to_writer
)
574 return method
.global
.to_s
.hash
+ local_class
.to_s
.hash
576 redef fun == ( other
)
578 return other
isa MMExplicitImport and
579 method
== other
.method
and local_class
== other
.local_class