--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2011 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stub generator for modules using the native interface
+module nits
+
+import parser
+import syntax
+import metamodel
+import analysis
+import abstracttool
+import native_interface
+
+class NitStubGenerator
+ super AbstractCompiler
+
+ var opt_in_place: OptionBool = new OptionBool("Generate stub files as .nit.[ch] instead of .stub.nit.[ch]", "-i", "--in-place")
+
+ init
+ do
+ super( "nits" )
+
+ option_context.add_option(opt_in_place)
+ end
+
+ redef fun perform_work(mods)
+ do
+ for mod in mods do
+ assert mod isa MMSrcModule
+
+ # TODO check if extern hybrid
+
+ var visitor = new StubVisitor( opt_in_place.value )
+
+ # actually compil stub
+ mod.generate_stub( visitor )
+
+ # write to file
+ var mod_base_path = "{mod.directory.path}/{mod.name}"
+ visitor.write_to_files( mod_base_path )
+ end
+ end
+end
+
+
+redef class MMModule
+ fun generate_stub( v: StubVisitor )
+ do
+ ### header comments
+ var module_info = "/*\n\tExtern implementation of Nit module {name}\n"
+ v.header_head.add( module_info )
+ v.body_head.add( module_info )
+
+ # instructions to rename
+ if not v.in_place then
+ v.header_head.add( "\tFile initially created by nits to implement extern methods body\n" )
+ v.body_head.add( "\tFile initially created by nits to customize type of extern classes\n" )
+ end
+
+ v.header_head.add( "*/\n\n" )
+ v.body_head.add( "*/\n\n" )
+ ### end of header comments
+
+ # header file guard
+ var guard = "{name.to_s.to_upper}_NIT_H"
+ v.header_head.add( "#ifndef {guard}\n#define {guard}\n\n" )
+
+ ### imports
+ # import standard .nit.h file
+ v.body_head.add( "#include \"{name}.nit.h\"\n" )
+
+ # import autogenerated frontier header file
+ v.header_head.add( "#include <{name}._nitni.h>\n\n" )
+ ### end of import
+
+ for local_class in local_classes do
+ ### extern methods
+ for prop in local_class.local_local_properties do
+ # if defined of redefined in this module
+ # and is extern
+ if prop.mmmodule == self and
+ prop isa MMSrcMethod and prop.is_extern then
+ prop.generate_stub( v )
+ end
+ end
+
+ ### extern classes
+ # if class is extern and defined here first
+ if local_class.global.intro == local_class and
+ local_class.global.is_extern then
+ local_class.generate_stub( v )
+ end
+ end
+
+ # header file guard close
+ v.header_head.add( "#endif\n" )
+ end
+end
+
+redef class MMSrcMethod
+ fun generate_stub( v: StubVisitor )
+ do
+ ### documentation to guide the user
+ var helper_documentation = new Writer
+
+ # title comment
+ helper_documentation.add( "C implementation of {full_name}" )
+
+ # TODO add nitdoc comment
+
+ # explicit extern calls signatures in comment
+ var imported_signatures = new Array[String]
+ for extern_call in explicit_imports do
+ var meth = extern_call.method
+ imported_signatures.add( "\t{meth.friendly_csignature(extern_call.local_class)} for {meth.full_name}" )
+ end
+
+ # explicit extern casts
+ for cast in explicit_casts do
+ if not ( cast.is_about_nullable_only and
+ cast.is_not_null_to_nullable ) then
+ imported_signatures.add( "\t{cast.is_a_friendly_csignature} to check if a {cast.from} is a {cast.to}" )
+ end
+
+ imported_signatures.add( "\t{cast.as_friendly_csignature} to cast from {cast.from} to {cast.to}" )
+ end
+
+ # explicit extern casts
+ if need_super then
+ imported_signatures.add( "\t{friendly_super_csignature} to call super" )
+ end
+
+ if imported_signatures.length > 0 then
+ helper_documentation.add("\n\nImported methods signatures:\n" )
+ helper_documentation.add_all( imported_signatures, "\n")
+ end
+
+ v.body_impl.add( "\n/*\n" )
+ v.body_impl.append( helper_documentation )
+ v.body_impl.add( "\n*/\n" )
+ ### end of documentation
+
+ ### extern method implementation
+ v.header_decl.add( "{impl_csignature};\n" )
+
+ v.body_impl.add( "{impl_csignature} \{" )
+
+ v.body_impl.add( "\}\n" )
+ ### end of implementation
+ end
+end
+
+redef class MMLocalClass
+ fun generate_stub( v: StubVisitor )
+ do
+ v.header_head.add( "#define {get_type.friendly_extern_name} void*\n" )
+ end
+end
+
+class StubVisitor
+ # comments, imports (auto and custom from inline), types
+ var header_head : Writer = new Writer
+
+ # implementation declaration for extern methods
+ var header_decl : Writer = new Writer
+
+ # comments, imports and custom code from inline
+ var body_head : Writer = new Writer
+
+ # implementation body of extern methods
+ var body_impl : Writer = new Writer
+
+ # generates final .nit.[ch] instead of stub files .sub.nit.[ch]
+ var in_place : Bool
+
+ init ( in_place : Bool ) do self.in_place = in_place
+
+ # write stubs to disk
+ fun write_to_files( base_path : String )
+ do
+ var mid_ext = if in_place then ".nit" else ".stub.nit"
+
+ var stream = new OFStream.open( "{base_path}{mid_ext}.h" )
+ header_head.write_to_stream( stream )
+ header_decl.write_to_stream( stream )
+ stream.close
+
+ stream = new OFStream.open( "{base_path}{mid_ext}.c" )
+ body_head.write_to_stream( stream )
+ body_impl.write_to_stream( stream )
+ stream.close
+ end
+end
+
+var nits = new NitStubGenerator
+nits.exec_cmd_line