# Create a directory (and all intermediate directories if needed)
#
+ # The optional `mode` parameter specifies the permissions of the directory,
+ # the default value is `0o777`.
+ #
# Return an error object in case of error.
#
# assert "/etc/".mkdir != null
- fun mkdir: nullable Error
+ fun mkdir(mode: nullable Int): nullable Error
do
+ mode = mode or else 0o777
+
var dirs = self.split_with("/")
var path = new FlatBuffer
if dirs.is_empty then return null
if d.is_empty then continue
path.append(d)
path.add('/')
- var res = path.to_s.to_cstring.file_mkdir
+ var res = path.to_s.to_cstring.file_mkdir(mode)
if not res and error == null then
error = new IOError("Cannot create directory `{path}`: {sys.errno.strerror}")
end
return stat_element;
`}
- private fun file_mkdir: Bool `{ return !mkdir(self, 0777); `}
+ private fun file_mkdir(mode: Int): Bool `{ return !mkdir(self, mode); `}
private fun rmdir: Bool `{ return !rmdir(self); `}
#
# In nitni files, declare internal function as extern
- var full_friendly_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind})"
+ var full_friendly_csignature = "int {v.compiler.mainmodule.c_name }___{from.mangled_cname}_is_a_{to.mangled_cname}({from.cname_blind})"
ccu.header_decl.add("extern {full_friendly_csignature};\n")
# In nitni files, #define friendly as extern
- ccu.header_decl.add("#define {check_cname} {v.compiler.mainmodule.name}___{check_cname}\n")
+ ccu.header_decl.add "#ifndef {check_cname}\n"
+ ccu.header_decl.add "#define {check_cname} {v.compiler.mainmodule.c_name}___{check_cname}\n"
+ ccu.header_decl.add "#endif\n"
if compile_implementation_too then
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
- var full_internal_csignature = "int {v.compiler.mainmodule.name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
+ var full_internal_csignature = "int {v.compiler.mainmodule.c_name }___{from.mangled_cname}_is_a_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
nitni_visitor.add_decl("/* nitni check for {from} to {to} */")
nitni_visitor.add_decl("{full_internal_csignature} \{")
# special checks
if from == to.as_nullable then
# format A_is_null
- ccu.header_decl.add("#define {from.mangled_cname}_is_null !{from.mangled_cname}_is_a_{to.mangled_cname}\n")
+ ccu.header_decl.add "#ifndef {from.mangled_cname}_is_null\n"
+ ccu.header_decl.add "#define {from.mangled_cname}_is_null !{from.mangled_cname}_is_a_{to.mangled_cname}\n"
+ ccu.header_decl.add "#endif\n"
end
#
#
# In nitni files, declare internal function as extern
- full_friendly_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind})"
+ full_friendly_csignature = "{to.cname_blind} {v.compiler.mainmodule.c_name }___{from.mangled_cname}_as_{to.mangled_cname}({from.cname_blind})"
ccu.header_decl.add("extern {full_friendly_csignature};\n")
# In nitni files, #define friendly as extern
- ccu.header_decl.add("#define {cast_cname} {v.compiler.mainmodule.name}___{cast_cname}\n")
+ ccu.header_decl.add "#ifndef {cast_cname}\n"
+ ccu.header_decl.add "#define {cast_cname} {v.compiler.mainmodule.c_name}___{cast_cname}\n"
+ ccu.header_decl.add "#endif\n"
if compile_implementation_too then
# Internally, implement internal function
var nitni_visitor = v.compiler.new_visitor
nitni_visitor.frame = v.frame
- var full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
+ var full_internal_csignature = "{to.cname_blind} {v.compiler.mainmodule.c_name }___{from.mangled_cname}_as_{to.mangled_cname}({internal_call_context.name_mtype(from)} from)"
nitni_visitor.add_decl("/* nitni cast for {from} to {to} */")
nitni_visitor.add_decl("{full_internal_csignature} \{")
# special casts
if from.as_nullable == to then
# format A_as_nullable
- ccu.header_decl.add("#define {from.mangled_cname}_as_nullable {from.mangled_cname}_as_{to.mangled_cname}\n")
+ ccu.header_decl.add "#ifndef {from.mangled_cname}_as_nullable\n"
+ ccu.header_decl.add "#define {from.mangled_cname}_as_nullable {from.mangled_cname}_as_{to.mangled_cname}\n"
+ ccu.header_decl.add "#endif\n"
end
if from == to.as_nullable then
# format A_as_nullable
- ccu.header_decl.add("#define {to.mangled_cname}_as_not_nullable {from.mangled_cname}_as_{to.mangled_cname}\n")
+ ccu.header_decl.add "#ifndef {to.mangled_cname}_as_not_nullable\n"
+ ccu.header_decl.add "#define {to.mangled_cname}_as_not_nullable {from.mangled_cname}_as_{to.mangled_cname}\n"
+ ccu.header_decl.add "#endif\n"
end
end
end
import nitni
import ffi
import naive_interpreter
+import debugger_socket # To linearize `ToolContext::init`
+
+redef class ToolContext
+
+ # --compile-dir
+ var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
+
+ init do option_context.add_option opt_compile_dir
+end
redef class AMethPropdef
# Does this method definition use the FFI and is it supported by the interpreter?
end
redef class NaiveInterpreter
+ redef fun start(mainmodule)
+ do
+ super
+
+ # Delete temporary files
+ var compile_dir = compile_dir
+ if compile_dir.file_exists then compile_dir.rmdir
+ end
+
# Where to store generated C and extracted code
- #
- # TODO make customizable and delete when execution completes
- private var compile_dir = "nit_compile"
+ private var compile_dir: String is lazy do
+ # Prioritize the user supplied directory
+ var opt = modelbuilder.toolcontext.opt_compile_dir.value
+ if opt != null then return opt
+ return "/tmp/niti_ffi_{process_id}"
+ end
+
+ # Identifier for this process, unique between running interpreters
+ private fun process_id: Int `{ return getpid(); `}
# Path of the compiled foreign code library
#
var compile_dir = v.compile_dir
var foreign_code_lib_path = v.foreign_code_lib_path(mmodule)
- if not compile_dir.file_exists then compile_dir.mkdir
+ if not compile_dir.file_exists then compile_dir.mkdir(0o700)
# Compile the common FFI part
ensure_compile_ffi_wrapper
redef class MMethod
# Build a C function name for the FFI implementation (uses friendly naming).
- # * On a specific static receiver mype `recv_mtype`
+ # * On a specific static receiver type `recv_mtype`
# * In referene to the module `from_module` (used for type resolving and as a possible prefix)
# * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
# * With a specified length indicating whether it uses the sort name or the long name with
if suffix != null then cname = "{cname}{suffix}"
- if length.long then cname = "{from_mmodule.name}___{cname}"
+ if length.long then cname = "{from_mmodule.c_name}___{cname}"
return cname
end
# Build a C function signature for the FFI implementation (uses friendly naming).
- # * On a specific static receiver mype `recv_mtype`
+ # * On a specific static receiver type `recv_mtype`
# * In referene to the module `from_module` (used for type resolving and as a possible prefix)
# * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
# * With a specified length indicating whether it uses the sort name or the long name with
end
# Build a C function call for the FFI implementation (uses friendly naming).
- # * On a specific static receiver mype `recv_mtype`
+ # * On a specific static receiver type `recv_mtype`
# * In referene to the module `from_module` (used for type resolving and as a possible prefix)
# * Has a possible `suffix` to the method name (may be "__super", "__impl", null, etc.)
# * With a specified length indicating whether it uses the sort name or the long name with