From e38b6be796cad69db5a9582796bca3ae62f95e54 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alexis=20Laferri=C3=A8re?= Date: Fri, 8 May 2015 08:53:10 -0400 Subject: [PATCH] src/ffi: separate ffi::ffi_base in light/full modules MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexis Laferrière --- src/ffi/ffi_base.nit | 171 +------------------------------------- src/ffi/light_ffi_base.nit | 198 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 169 deletions(-) create mode 100644 src/ffi/light_ffi_base.nit diff --git a/src/ffi/ffi_base.nit b/src/ffi/ffi_base.nit index b8a8103..963df27 100644 --- a/src/ffi/ffi_base.nit +++ b/src/ffi/ffi_base.nit @@ -22,184 +22,17 @@ import parser import modelbuilder import nitni -redef class ToolContext - var ffi_language_assignation_phase: Phase = new FFILanguageAssignationPhase(self, null) -end - -class FFILanguageAssignationPhase - super Phase - - # All supported languages - var languages = new Array[FFILanguage] - - redef fun process_nmodule(nmodule) - do - for block in nmodule.n_extern_code_blocks do - verify_foreign_code_on_node( block ) - end - end - - redef fun process_npropdef(npropdef) - do - if npropdef isa AMethPropdef then - var code_block = npropdef.n_extern_code_block - if code_block != null then - verify_foreign_code_on_node( code_block ) - end - end - end - - redef fun process_nclassdef(nclassdef) - do - if nclassdef isa AStdClassdef and nclassdef.n_extern_code_block != null then - verify_foreign_code_on_node( nclassdef.n_extern_code_block.as(not null) ) - end - end - - private fun verify_foreign_code_on_node(n: AExternCodeBlock) - do - var found = false - for v in languages do - var identified = v.identify_language(n) - if identified then - if found and identified then - toolcontext.error(n.location, "FFI Error: two languages identified as possible handlers.") - end - n.language = v - found = true - end - end - - if not found then toolcontext.error(n.location, "FFI Error: unsupported language.") - end -end +import light_ffi_base redef class MModule - var ffi_files = new Array[ExternFile] - # Callbacks used by this module, classified by language var ffi_callbacks = new HashMap[FFILanguage, Set[NitniCallback]] end -redef class AExternCodeBlock - fun language_name: nullable String do - if n_in_language == null then return null - return n_in_language.n_string.without_quotes - end - fun language_name_lowered: nullable String do - if language_name == null then return null - return language_name.to_lower - end - - fun code: String do return n_extern_code_segment.without_guard - - var language: nullable FFILanguage = null -end - # Visitor for a specific languages. Works kinda like a `Phase` and is executed # by a `Phase`. -class FFILanguage - var ffi_language_assignation_phase: FFILanguageAssignationPhase - - init - do - ffi_language_assignation_phase.languages.add(self) - end - - # Is this `block` written in this language? - fun identify_language(block: AExternCodeBlock ): Bool is abstract - - # Generate wrapper code for this module/header code block - fun compile_module_block(block: AExternCodeBlock, ecc: CCompilationUnit, mmodule: MModule) is abstract - - # Generate wrapper code for this extern method - fun compile_extern_method(block: AExternCodeBlock, m: AMethPropdef, - ecc: CCompilationUnit, nmodule: MModule) is abstract - - # Generate wrapper code for this extern class - fun compile_extern_class(block: AExternCodeBlock, m: AClassdef, - ecc: CCompilationUnit, mmodule: MModule) is abstract - - # Get the foreign type of this extern class definition - fun get_ftype(block: AExternCodeBlock, m: AClassdef): ForeignType is abstract - +redef class FFILanguage # Generate the code to offer this callback if foreign code fun compile_callback(callback: NitniCallback, mmodule: MModule, mainmmodule: MModule, ecc: CCompilationUnit) is abstract - - # Complete compilation of generated code - fun compile_to_files(mmodule: MModule, directory: String) do end -end - -redef class TString - # Returns the content of this node without both of the surrounding " - fun without_quotes: String - do - assert text.length >= 2 - return text.substring(1, text.length-2) - end -end - -redef class TExternCodeSegment - # Returns the content of this node without the surrounding `{ and `} - fun without_guard: String - do - assert text.length >= 4 - return text.substring(2, text.length-4) - end -end - -redef class CCompilationUnit - fun write_as_impl(mmodule: MModule, compdir: String) - do - var base_name = "{mmodule.c_name}._ffi" - - var h_file = "{base_name}.h" - var guard = "{mmodule.c_name.to_upper}_NIT_H" - write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard) - - var c_file = "{base_name}.c" - write_body_to_file(mmodule, "{compdir}/{c_file}", ["", "", "\"{h_file}\""]) - - files.add( "{compdir}/{c_file}" ) - end - - fun write_header_to_file(mmodule: MModule, file: String, includes: Array[String], guard: String) - do - var stream = new FileWriter.open( file ) - - # header comments - var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n" - - stream.write( module_info ) - - stream.write( "#ifndef {guard}\n" ) - stream.write( "#define {guard}\n\n" ) - - for incl in includes do stream.write( "#include {incl}\n" ) - - compile_header_core( stream ) - - # header file guard close - stream.write( "#endif\n" ) - stream.close - end - - fun write_body_to_file(mmodule: MModule, file: String, includes: Array[String]) - do - var stream = new FileWriter.open(file) - - var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n" - - stream.write( module_info ) - for incl in includes do stream.write( "#include {incl}\n" ) - - compile_body_core( stream ) - - stream.close - end -end - -class ForeignType - fun ctype: String do return "void*" end diff --git a/src/ffi/light_ffi_base.nit b/src/ffi/light_ffi_base.nit new file mode 100644 index 0000000..e3014a5 --- /dev/null +++ b/src/ffi/light_ffi_base.nit @@ -0,0 +1,198 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2012 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. +# 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. + +# Tools and utilities for language targetted FFI implementations +module light_ffi_base + +import c_tools +import parser +import modelbuilder +import nitni::nitni_utilities + +redef class ToolContext + var ffi_language_assignation_phase: Phase = new FFILanguageAssignationPhase(self, null) +end + +class FFILanguageAssignationPhase + super Phase + + # All supported languages + var languages = new Array[FFILanguage] + + redef fun process_nmodule(nmodule) + do + for block in nmodule.n_extern_code_blocks do + verify_foreign_code_on_node( block ) + end + end + + redef fun process_npropdef(npropdef) + do + if npropdef isa AMethPropdef then + var code_block = npropdef.n_extern_code_block + if code_block != null then + verify_foreign_code_on_node( code_block ) + end + end + end + + redef fun process_nclassdef(nclassdef) + do + if nclassdef isa AStdClassdef and nclassdef.n_extern_code_block != null then + verify_foreign_code_on_node( nclassdef.n_extern_code_block.as(not null) ) + end + end + + private fun verify_foreign_code_on_node(n: AExternCodeBlock) + do + var found = false + for v in languages do + var identified = v.identify_language(n) + if identified then + if found and identified then + toolcontext.error(n.location, "FFI Error: two languages identified as possible handlers.") + end + n.language = v + found = true + end + end + + if not found then toolcontext.error(n.location, "FFI Error: unsupported language.") + end +end + +redef class MModule + var ffi_files = new Array[ExternFile] +end + +redef class AExternCodeBlock + fun language_name: nullable String do + if n_in_language == null then return null + return n_in_language.n_string.without_quotes + end + fun language_name_lowered: nullable String do + if language_name == null then return null + return language_name.to_lower + end + + fun code: String do return n_extern_code_segment.without_guard + + var language: nullable FFILanguage = null +end + +# Visitor for a specific languages. Works kinda like a `Phase` and is executed +# by a `Phase`. +class FFILanguage + var ffi_language_assignation_phase: FFILanguageAssignationPhase + + init + do + ffi_language_assignation_phase.languages.add(self) + end + + # Is this `block` written in this language? + fun identify_language(block: AExternCodeBlock ): Bool is abstract + + # Generate wrapper code for this module/header code block + fun compile_module_block(block: AExternCodeBlock, ecc: CCompilationUnit, mmodule: MModule) is abstract + + # Generate wrapper code for this extern method + fun compile_extern_method(block: AExternCodeBlock, m: AMethPropdef, + ecc: CCompilationUnit, nmodule: MModule) is abstract + + # Generate wrapper code for this extern class + fun compile_extern_class(block: AExternCodeBlock, m: AClassdef, + ecc: CCompilationUnit, mmodule: MModule) is abstract + + # Get the foreign type of this extern class definition + fun get_ftype(block: AExternCodeBlock, m: AClassdef): ForeignType is abstract + + # Complete compilation of generated code + fun compile_to_files(mmodule: MModule, directory: String) do end +end + +redef class TString + # Returns the content of this node without both of the surrounding " + fun without_quotes: String + do + assert text.length >= 2 + return text.substring(1, text.length-2) + end +end + +redef class TExternCodeSegment + # Returns the content of this node without the surrounding `{ and `} + fun without_guard: String + do + assert text.length >= 4 + return text.substring(2, text.length-4) + end +end + +redef class CCompilationUnit + fun write_as_impl(mmodule: MModule, compdir: String) + do + var base_name = "{mmodule.c_name}._ffi" + + var h_file = "{base_name}.h" + var guard = "{mmodule.c_name.to_upper}_NIT_H" + write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard) + + var c_file = "{base_name}.c" + write_body_to_file(mmodule, "{compdir}/{c_file}", ["", "", "\"{h_file}\""]) + + files.add( "{compdir}/{c_file}" ) + end + + fun write_header_to_file(mmodule: MModule, file: String, includes: Array[String], guard: String) + do + var stream = new FileWriter.open( file ) + + # header comments + var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n" + + stream.write( module_info ) + + stream.write( "#ifndef {guard}\n" ) + stream.write( "#define {guard}\n\n" ) + + for incl in includes do stream.write( "#include {incl}\n" ) + + compile_header_core( stream ) + + # header file guard close + stream.write( "#endif\n" ) + stream.close + end + + fun write_body_to_file(mmodule: MModule, file: String, includes: Array[String]) + do + var stream = new FileWriter.open(file) + + var module_info = "/*\n\tExtern implementation of Nit module {mmodule.name}\n*/\n" + + stream.write( module_info ) + for incl in includes do stream.write( "#include {incl}\n" ) + + compile_body_core( stream ) + + stream.close + end +end + +class ForeignType + fun ctype: String do return "void*" +end -- 1.7.9.5