tools: adds nits, a compiler of help files to use the native interface
authorAlexis Laferrière <alexis.laf@xymus.net>
Thu, 18 Aug 2011 20:57:13 +0000 (16:57 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Thu, 9 Feb 2012 21:00:52 +0000 (16:00 -0500)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

.gitignore
Makefile
src/nits.nit [new file with mode: 0644]
tests/Makefile
tests/sav/nits.sav [new file with mode: 0644]

index a4d3ff1..d54ff3f 100644 (file)
@@ -38,3 +38,5 @@ tests/alt
 tests/errlist
 tests/test_nitc_logs
 tests/hello_world
+
+*.stub.nit.[ch]
index fa95668..117dad5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 NITCOPT=
 
-all: bin/nitc bin/nitdoc doc/stdlib/index.html
+all: bin/nitc bin/nitdoc doc/stdlib/index.html bin/nits
 
 bin/nitc: c_src/nitc src/parser/parser.nit
        @echo '***************************************************************'
@@ -32,6 +32,12 @@ bin/nitdoc: bin/nitc
        src/git-gen-version.sh
        bin/nitc ${NITCOPT} -o bin/nitdoc -O -v src/nitdoc.nit
 
+bin/nits: bin/nitc
+       @echo '***************************************************************'
+       @echo '* Compile nits from NIT source files                        *'
+       @echo '***************************************************************'
+       bin/nitc ${NITCOPT} -o bin/nits -O -v src/nits.nit
+
 doc/stdlib/index.html: bin/nitdoc
        @echo '***************************************************************'
        @echo '* Generate doc for NIT standard library                       *'
diff --git a/src/nits.nit b/src/nits.nit
new file mode 100644 (file)
index 0000000..d2c0742
--- /dev/null
@@ -0,0 +1,209 @@
+# 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
index a45286a..b75c520 100644 (file)
@@ -8,7 +8,7 @@ some:
        ./tests.sh base_compile.nit base_attr.nit base_gen.nit test_gen_inh.nit bench_fib.nit example_objet.nit
 
 global:
-       ./tests.sh -o --global *.nit ../examples/*.nit ../lib/*.nit ../src/nitdoc.nit ../src/nitc.nit ../src/test_parser.nit
+       ./tests.sh -o --global *.nit ../examples/*.nit ../lib/*.nit ../src/nitdoc.nit ../src/nitc.nit../src/nits.nit ../src/test_parser.nit
 
 icode:
        ./tests_icode.sh icode*.nit
diff --git a/tests/sav/nits.sav b/tests/sav/nits.sav
new file mode 100644 (file)
index 0000000..92b0452
--- /dev/null
@@ -0,0 +1,11 @@
+usage: nits [options] file...
+  -W, --warn         Show warnings
+  -I, --path         Set include path for loaders (may be used more than once)
+  --log              Generate various log files
+  --log-dir          Directory where to generate log files
+  --only-parse       Only proceed to parse step of loaders
+  --only-metamodel   Stop after meta-model processing
+  -h, -?, --help     Show Help (This screen)
+  --version          Show version and exit
+  -v, --verbose      Verbose
+  -i, --in-place     Generate stub files as .nit.[ch] instead of .stub.nit.[ch]