ni_nitdoc: added fast copy past utility to signatures.
[nit.git] / src / nits.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2011 Alexis Laferrière <alexis.laf@xymus.net>
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 # Stub generator for modules using the native interface
18 module nits
19
20 import parser
21 import syntax
22 import metamodel
23 import analysis
24 import abstracttool
25 import native_interface
26
27 class NitStubGenerator
28 super AbstractCompiler
29
30 var opt_in_place: OptionBool = new OptionBool("Generate stub files as .nit.[ch] instead of .stub.nit.[ch]", "-i", "--in-place")
31
32 init
33 do
34 super( "nits" )
35
36 option_context.add_option(opt_in_place)
37 end
38
39 redef fun perform_work(mods)
40 do
41 for mod in mods do
42 assert mod isa MMSrcModule
43
44 if mod.is_extern_hybrid then
45 var visitor = new StubVisitor( opt_in_place.value )
46
47 # actually compile stub
48 mod.generate_stub( visitor )
49
50 # write to file
51 var mod_base_path = "{mod.directory.path}/{mod.name}"
52 visitor.write_to_files( mod_base_path )
53 end
54 end
55 end
56 end
57
58
59 redef class MMModule
60 fun generate_stub( v: StubVisitor )
61 do
62 ### header comments
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 )
66
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" )
71 end
72
73 v.header_head.add( "*/\n\n" )
74 v.body_head.add( "*/\n\n" )
75 ### end of header comments
76
77 # header file guard
78 var guard = "{name.to_s.to_upper}_NIT_H"
79 v.header_head.add( "#ifndef {guard}\n#define {guard}\n\n" )
80
81 ### imports
82 # import standard .nit.h file
83 v.body_head.add( "#include \"{name}.nit.h\"\n" )
84
85 # import autogenerated frontier header file
86 v.header_head.add( "#include <{name}._nitni.h>\n\n" )
87 ### end of import
88
89 for local_class in local_classes do
90 ### extern methods
91 for prop in local_class.local_local_properties do
92 # if defined of redefined in this module
93 # and is extern
94 if prop.mmmodule == self and
95 prop isa MMSrcMethod and prop.is_extern then
96 prop.generate_stub( v )
97 end
98 end
99
100 ### extern classes
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 )
105 end
106 end
107
108 # header file guard close
109 v.header_decl.add( "\n#endif\n" )
110 end
111 end
112
113 redef class MMSrcMethod
114 fun generate_stub( v: StubVisitor )
115 do
116 ### documentation to guide the user
117 var helper_documentation = new Writer
118
119 # title comment
120 helper_documentation.add( "C implementation of {full_name}" )
121
122 # TODO add nitdoc comment
123
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}" )
129 end
130
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}" )
136 end
137
138 imported_signatures.add( "\t{cast.as_friendly_csignature} to cast from {cast.from} to {cast.to}" )
139 end
140
141 # explicit extern super
142 if need_super then
143 imported_signatures.add( "\t{friendly_super_csignature} to call super" )
144 end
145
146 if imported_signatures.length > 0 then
147 helper_documentation.add("\n\nImported methods signatures:\n" )
148 helper_documentation.add_all( imported_signatures, "\n")
149 end
150
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
155
156 ### extern method implementation
157 v.header_decl.add( "{impl_csignature};\n" )
158
159 v.body_impl.add( "{impl_csignature}\n\{\n\}\n" )
160 ### end of implementation
161 end
162 end
163
164 redef class MMLocalClass
165 fun generate_stub( v: StubVisitor )
166 do
167 v.header_head.add( "#define {get_type.friendly_extern_name} void*\n" )
168 end
169 end
170
171 class StubVisitor
172 # comments, imports (auto and custom from inline), types
173 var header_head : Writer = new Writer
174
175 # implementation declaration for extern methods
176 var header_decl : Writer = new Writer
177
178 # comments, imports and custom code from inline
179 var body_head : Writer = new Writer
180
181 # implementation body of extern methods
182 var body_impl : Writer = new Writer
183
184 # generates final .nit.[ch] instead of stub files .sub.nit.[ch]
185 var in_place : Bool
186
187 init ( in_place : Bool ) do self.in_place = in_place
188
189 # write stubs to disk
190 fun write_to_files( base_path : String )
191 do
192 var mid_ext = if in_place then ".nit" else ".stub.nit"
193
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 )
197 stream.close
198
199 stream = new OFStream.open( "{base_path}{mid_ext}.c" )
200 body_head.write_to_stream( stream )
201 body_impl.write_to_stream( stream )
202 stream.close
203 end
204 end
205
206 var nits = new NitStubGenerator
207 nits.exec_cmd_line