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 # Stub generator for modules using the native interface
25 import native_interface
27 class NitStubGenerator
28 super AbstractCompiler
30 var opt_in_place
: OptionBool = new OptionBool("Generate stub files as .nit.[ch] instead of .stub.nit.[ch]", "-i", "--in-place")
36 option_context
.add_option
(opt_in_place
)
39 redef fun perform_work
(mods
)
42 assert mod
isa MMSrcModule
44 if mod
.is_extern_hybrid
then
45 var visitor
= new StubVisitor( opt_in_place
.value
)
47 # actually compile stub
48 mod
.generate_stub
( visitor
)
51 var mod_base_path
= "{mod.directory.path}/{mod.name}"
52 visitor
.write_to_files
( mod_base_path
)
60 fun generate_stub
( v
: StubVisitor )
63 var module_info
= "/*\n\tExtern implementation of Nit module {name}\n"
64 v
.header_head
.add
( module_info
)
65 v
.body_head
.add
( module_info
)
67 # instructions to rename
68 if not v
.in_place
then
69 v
.header_head
.add
( "\tFile initially created by nits to implement extern methods body\n" )
70 v
.body_head
.add
( "\tFile initially created by nits to customize type of extern classes\n" )
73 v
.header_head
.add
( "*/\n\n" )
74 v
.body_head
.add
( "*/\n\n" )
75 ### end of header comments
78 var guard
= "{name.to_s.to_upper}_NIT_H"
79 v
.header_head
.add
( "#ifndef {guard}\n#define {guard}\n\n" )
82 # import standard .nit.h file
83 v
.body_head
.add
( "#include \"{name}.nit
.h\
"\n" )
85 # import autogenerated frontier header file
86 v
.header_head
.add
( "#include <{name}._nitni.h>\n\n" )
89 for local_class
in local_classes
do
91 for prop
in local_class
.local_local_properties
do
92 # if defined of redefined in this module
94 if prop
.mmmodule
== self and
95 prop
isa MMSrcMethod and prop
.is_extern
then
96 prop
.generate_stub
( v
)
101 # if class is extern and defined here first
102 if local_class
.global
.intro
== local_class
and
103 local_class
.global
.is_extern
then
104 local_class
.generate_stub
( v
)
108 # header file guard close
109 v
.header_decl
.add
( "\n#endif\n" )
113 redef class MMSrcMethod
114 fun generate_stub
( v
: StubVisitor )
116 ### documentation to guide the user
117 var helper_documentation
= new Writer
120 helper_documentation
.add
( "C implementation of {full_name}" )
122 # TODO add nitdoc comment
124 # explicit extern calls signatures in comment
125 var imported_signatures
= new Array[String]
126 for extern_call
in explicit_imports
do
127 var meth
= extern_call
.method
128 imported_signatures
.add
( "\t{meth.friendly_csignature(extern_call.local_class)} for {meth.full_name}" )
131 # explicit extern casts
132 for cast
in explicit_casts
do
133 if not ( cast
.is_about_nullable_only
and
134 cast
.is_not_null_to_nullable
) then
135 imported_signatures
.add
( "\t{cast.is_a_friendly_csignature} to check if a {cast.from} is a {cast.to}" )
138 imported_signatures
.add
( "\t{cast.as_friendly_csignature} to cast from {cast.from} to {cast.to}" )
141 # explicit extern super
143 imported_signatures
.add
( "\t{friendly_super_csignature} to call super" )
146 if imported_signatures
.length
> 0 then
147 helper_documentation
.add
("\n\nImported methods signatures:\n" )
148 helper_documentation
.add_all
( imported_signatures
, "\n")
151 v
.body_impl
.add
( "\n/*\n" )
152 v
.body_impl
.append
( helper_documentation
)
153 v
.body_impl
.add
( "\n*/\n" )
154 ### end of documentation
156 ### extern method implementation
157 v
.header_decl
.add
( "{impl_csignature};\n" )
159 v
.body_impl
.add
( "{impl_csignature}\n\{\n\}\n" )
160 ### end of implementation
164 redef class MMLocalClass
165 fun generate_stub
( v
: StubVisitor )
167 v
.header_head
.add
( "#define {get_type.friendly_extern_name} void*\n" )
172 # comments, imports (auto and custom from inline), types
173 var header_head
: Writer = new Writer
175 # implementation declaration for extern methods
176 var header_decl
: Writer = new Writer
178 # comments, imports and custom code from inline
179 var body_head
: Writer = new Writer
181 # implementation body of extern methods
182 var body_impl
: Writer = new Writer
184 # generates final .nit.[ch] instead of stub files .sub.nit.[ch]
187 init ( in_place
: Bool ) do self.in_place
= in_place
189 # write stubs to disk
190 fun write_to_files
( base_path
: String )
192 var mid_ext
= if in_place
then ".nit" else ".stub.nit"
194 var stream
= new OFStream.open
( "{base_path}{mid_ext}.h" )
195 header_head
.write_to_stream
( stream
)
196 header_decl
.write_to_stream
( stream
)
199 stream
= new OFStream.open
( "{base_path}{mid_ext}.c" )
200 body_head
.write_to_stream
( stream
)
201 body_impl
.write_to_stream
( stream
)
206 var nits
= new NitStubGenerator