X-Git-Url: http://nitlanguage.org diff --git a/src/ffi/c.nit b/src/ffi/c.nit index 329d9a3..495d4e6 100644 --- a/src/ffi/c.nit +++ b/src/ffi/c.nit @@ -1,6 +1,6 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2012-2013 Alexis Laferrière +# Copyright 2012-2014 Alexis Laferrière # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,48 +14,143 @@ # 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. +# Support for nesting C code within a Nit program using its FFI 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 " ) +redef class FFILanguageAssignationPhase + var c_language: FFILanguage = new CLanguage(self) +end - fun is_c_body : Bool do return language == null or - language_lowered == "c" or language_lowered == "c body" +class CLanguage + super FFILanguage - fun is_c_header : Bool do return language_lowered == "c header" + redef fun identify_language(n) do return n.is_c - redef fun accept_ffi_visitor( v ) + redef fun compile_module_block(block, ecc, mmodule) 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 ) + if block.is_c_header then + ecc.header_custom.add block.location.as_line_pragma + ecc.header_custom.add "\n" + ecc.header_custom.add block.code + else if block.is_c_body then + ecc.body_impl.add block.location.as_line_pragma + ecc.body_impl.add "\n" + ecc.body_impl.add block.code end end -end -redef class MMMethod - redef fun accept_ffi_visitor( v ) + redef fun compile_extern_method(block, m, ecc, mmodule) 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 + var fc = new ExternCFunction(m, mmodule) + fc.decls.add( block.location.as_line_pragma ) + fc.exprs.add( block.code ) + ecc.add_exported_function( fc ) + end + + redef fun compile_extern_class(block, m, ecc, mmodule) do end + + redef fun get_ftype(block, m) do return new ForeignCType(block.code) + + redef fun compile_callback(callback, mmodule, mainmodule, ecc) + do + callback.compile_callback_to_c(mainmodule, ecc) end end +redef class AExternCodeBlock + fun is_c: Bool do return language_name == null or + language_name_lowered == "c" or language_name_lowered.has_prefix( "c " ) + + fun is_c_body: Bool do return language_name == null or + language_name_lowered == "c" or language_name_lowered == "c body" + + fun is_c_header: Bool do return language_name_lowered == "c header" +end + redef class Location - fun as_line_pragma : String + fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n" +end + +redef class MModule + # FIXME make nullable the key of `cflags`, `ldflags` and `cppflags` when + # supported by the bootstrap + + # Custom options for the C compiler (CFLAGS) + var cflags = new MultiHashMap[String, String] + + # Custom options for the C linker (LDFLAGS) + var ldflags = new MultiHashMap[String, String] + + # Additional libraries needed for the compilation + # Will be used with pkg-config + var pkgconfigs = new Array[String] +end + +class ForeignCType + super ForeignType + + redef var ctype: String +end + +redef class NitniCallback + fun compile_callback_to_c(mmodule: MModule, ffi_ccu: CCompilationUnit) do end +end + +redef class Object + # Context when calling user C code from generated code + fun to_c_call_context: ToCCallContext do return once new ToCCallContext + + # Context when calling generated code from user C code + fun from_c_call_context: FromCCallContext do return once new FromCCallContext +end + +redef class MExplicitCall + redef fun compile_callback_to_c(mmodule, ffi_ccu) + do + var mproperty = mproperty.as(MMethod) + + var full_cname = mproperty.build_cname(recv_mtype, mmodule, null, long_signature) + var friendly_cname = mproperty.build_cname(recv_mtype, mmodule, null, short_signature) + ffi_ccu.body_decl.add("#define {friendly_cname} {full_cname}\n") + end +end + +# Context when calling user C code from generated code +class ToCCallContext + super CallContext + + # TODO: private init because singleton instance (see `to_c_call_context`) + + redef fun name_mtype(mtype) do - return "#line {line_start} \"{file.filename}\"\n" + if mtype isa MClassType and mtype.mclass.kind == extern_kind then return "void *" + return mtype.cname + end +end + +# Context when calling generated code from user C code +class FromCCallContext + super CallContext + + # TODO: private init because singleton instance (see `from_c_call_context`) + + redef fun name_mtype(mtype) do return mtype.cname +end + +class ExternCFunction + super CFunction + + var method: AMethPropdef + + init (method: AMethPropdef, mmodule: MModule) + do + self.method = method + + var recv_mtype = method.mpropdef.mclassdef.bound_mtype + var csignature = method.mpropdef.mproperty.build_csignature(recv_mtype, mmodule, "___impl", long_signature, from_c_call_context) + + super( csignature ) end end