native_body = native_name + "_nit.c"
if native_body.file_exists then cprogram.files.add(native_body)
end
+ if uses_ffi then
+ var ffi_header_name = "{cname}._ffi.h"
+ v.add_decl("#include \"{ffi_header_name}\"")
+ var ffi_body_name = "{cname}._ffi.c"
+ cprogram.files.add( "{cprogram.compdir}/{ffi_body_name}" )
+ end
end
declare_class_tables_to_c(v)
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 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.
+
+# Handles C inline code
+# Wraps all code in a thin wrapper.
+module c
+
+import ffi_base
+
+redef class ExternCode
+ fun is_c : Bool do return language == null or
+ language_lowered == "c" or language_lowered.has_prefix( "c " )
+
+ fun is_c_body : Bool do return language == null or
+ language_lowered == "c" or language_lowered == "c body"
+
+ fun is_c_header : Bool do return language_lowered == "c header"
+
+ redef fun accept_ffi_visitor( v )
+ do
+ if is_c_header then
+ v.compilation_unit.header_custom.add( code )
+ else if is_c_body then
+ v.compilation_unit.body_custom.add( code )
+ end
+ end
+end
+
+redef class MMMethod
+ redef fun accept_ffi_visitor( v )
+ do
+ if extern_implementation.is_c then
+ var fc = new CFunction( impl_csignature )
+ fc.decls.add( extern_implementation.location.as_line_pragma )
+ fc.exprs.add( extern_implementation.code )
+ v.compilation_unit.add_exported_function( fc )
+ else
+ super
+ end
+ end
+end
+
+redef class Location
+ fun as_line_pragma : String
+ do
+ return "#line {line_start} \"{file.filename}\"\n"
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 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.
+
+# This module implements the FFI with different languages
+module ffi
+
+import c
+
+redef class MMSrcModule
+ redef fun compile_separate_module(cprogram: CProgram)
+ do
+ super
+
+ if is_extern_hybrid then
+ var visitor = new FFIVisitor( cprogram.program.tc, self )
+ # TODO use cprogram to add generated files?
+
+ # actually compile stub
+ accept_ffi_visitor( visitor )
+
+ # write to file
+ if uses_ffi then
+ visitor.compile
+ end
+ end
+ end
+end
+
+redef class MMLocalClass
+ super FFIVisited
+end
+
+redef class FFIVisitor
+ fun compile
+ do
+ var compdir = tc.compdir.as(not null)
+ var base_name = "{mmmodule.cname}._ffi"
+ var c_file = "{base_name}.c"
+ var h_file = "{base_name}.h"
+
+ # header comments
+ var module_info = "/*\n\tExtern implementation of Nit module {mmmodule.name}\n*/\n"
+
+ # header file guard
+ var guard = "{mmmodule.cname.to_s.to_upper}_NIT_H"
+
+ # .h
+ var stream = new OFStream.open( "{compdir}/{h_file}" )
+ stream.write( module_info )
+ stream.write( "#include <{mmmodule.name}._nitni.h>\n\n" )
+ stream.write( "#ifndef {guard}\n" )
+ stream.write( "#define {guard}\n\n" )
+ compilation_unit.header_c_base.write_to_stream( stream )
+ compilation_unit.header_custom.write_to_stream( stream )
+ compilation_unit.header_c_types.write_to_stream( stream )
+ compilation_unit.header_decl.write_to_stream( stream )
+ stream.write( "#endif\n" )
+ stream.close
+
+ # .c
+ stream = new OFStream.open( "{compdir}/{c_file}" )
+ stream.write( module_info )
+ stream.write( "#include \"{h_file}\"\n" )
+ compilation_unit.body_decl.write_to_stream( stream )
+ compilation_unit.body_custom.write_to_stream( stream )
+ compilation_unit.body_impl.write_to_stream( stream )
+ stream.close
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012-2013 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.
+
+module ffi_base
+
+import native_interface
+import syntax # TODO move extern_implementation to MM
+import c_tools
+
+interface FFIVisited
+ fun accept_ffi_visitor( v : FFIVisitor ) do end
+end
+
+redef class ExternCode
+ super FFIVisited
+
+ # last resort for extern method
+ # assumes this is a code block in the root of a module
+ # should never be called if the extern method is implemented inline by a known language
+ redef fun accept_ffi_visitor( v )
+ do
+ var language = self.language
+ if language != null then
+ v.tc.warning( null, "language \"{language}\" used to implement a code block in {v.mmmodule} is unknown." )
+ else
+ v.tc.warning( null, "please specify a language to implement code blocks in {v.mmmodule}." ) # is ok with spec as of now, won't be raised
+ end
+ end
+
+ var language_lowered : nullable String = null
+
+ redef init ( language, code, loc )
+ do
+ super
+ if language != null then language_lowered = language.to_lower
+ end
+end
+
+redef class MMMethod
+ super FFIVisited
+
+ # last resort for extern method
+ # should never be called if the extern method is implemented inline by a known language
+ redef fun accept_ffi_visitor( v )
+ do
+ if extern_implementation != null then
+ var language = extern_implementation.language
+ if language != null then
+ v.tc.warning( null, "language \"{language}\" used to implement {full_name} is unknown." )
+ else
+ v.tc.warning( null, "please specify a language to implement {full_name}." ) # is ok with spec as of now, won't be raised
+ end
+ end
+ end
+end
+
+# set of extern imports in a language to be used by a module
+# FIXME move to native_interface or MM?
+class ExternImportSet
+ # set of imported functions, cached to avoid repetitions
+ var callbacks : Set[ MMExplicitImport ] = new HashSet[ MMExplicitImport ]
+
+ # set of imported functions, cached to avoid repetitions
+ var supers : Set[ MMExplicitImport ] = new HashSet[ MMExplicitImport ]
+
+ # set of relevant types, cached to avoid repetitions
+ var types : Set[ MMType ] = new HashSet[ MMType ]
+
+ # set of imported casts and as, cached to avoid repetitions
+ var casts : Set[ MMImportedCast ] = new HashSet[ MMImportedCast ]
+end
+
+redef class MMLocalClass
+ super FFIVisited
+
+ fun c_type : nullable String do return null
+end
+
+redef class MMModule
+ super FFIVisited
+
+ redef fun accept_ffi_visitor( v )
+ do
+ for local_class in local_classes do
+ # if class is extern and defined here first
+ if local_class.global.intro == local_class and
+ local_class.global.is_extern then
+ local_class.accept_ffi_visitor( v )
+ end
+
+ 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 MMMethod and prop.is_extern and
+ prop.extern_implementation != null then
+ prop.accept_ffi_visitor( v )
+ end
+ end
+
+ end
+
+ for block in extern_code_blocks do block.accept_ffi_visitor( v )
+ end
+end
+
+class FFIVisitor
+ var tc : ToolContext
+
+ # module being visited
+ var mmmodule : MMModule
+
+ var compilation_unit = new CCompilationUnit
+end
+
v.body.add( "#include \"{path}\"\n" )
v.header.add( "#include \"{path}\"\n" )
end
+ if uses_ffi then
+ v.header.add( "#include <{cname}._ffi.h>\n" )
+ end
for local_class in local_classes do
### extern methods
end
end
+ v.compile_cached
+
v.header.add( "#endif\n" )
end
end
var cprogram : CProgram
+ # compiles cached types and callbacks
fun compile_cached
do
# types
var visitor = new FrontierVisitor( self, cprogram )
compile_frontier( visitor )
- visitor.compile_cached
-
var base_path = "{cprogram.compdir}/{name}"
visitor.write_to_files( base_path )
end
import syntax
import native_interface
import separate_options
+import ffi
# The main class of the nitcompiler program
class NitCompiler
# only to order correctly redefs of compile_separate_module
import native_interface
+import ffi
redef class ToolContext
# all ops precised in .ops files