X-Git-Url: http://nitlanguage.org diff --git a/src/compiling/compiling_base.nit b/src/compiling/compiling_base.nit index c5bf61d..24d4fcb 100644 --- a/src/compiling/compiling_base.nit +++ b/src/compiling/compiling_base.nit @@ -17,19 +17,108 @@ # Common things for NIT compilation and C generation package compiling_base -import syntax +import mmloader private import utils +import primitive_info +import program +import compiling_writer redef class ToolContext - readable writable attr _global: Bool - readable writable attr _attr_sim: Bool - readable writable attr _base_dir: String - readable writable attr _clibdir: String - readable writable attr _bindir: String - readable writable attr _output_file: String - readable writable attr _boost: Bool - readable writable attr _no_cc: Bool - readable writable attr _ext_prefix: String + readable writable var _compdir: nullable String = null + readable writable var _clibdir: nullable String = null + readable writable var _bindir: nullable String = null + readable writable var _output_file: nullable String = null + readable writable var _boost: Bool = false + readable writable var _no_cc: Bool = false + readable writable var _cc_link: Bool = false + readable writable var _cc_libs: Array[String] = new Array[String] + readable writable var _cc_lib_paths: Array[String] = new Array[String] + readable writable var _cc_include_paths: Array[String] = new Array[String] + readable writable var _ext_prefix: String = "" +end + +# A program that is compiled to C +class CProgram + init(p: Program) + do + _program = p + _compdir = p.tc.compdir.as(not null) + _build_file = "{compdir}/{program.main_module.name}._build.sh" + end + + # The Nit program compiled to C + readable var _program: Program + + # C files (full path) required to compile + readable var _files: Array[String] = new Array[String] + + # Includes paths (gcc -I) required to find the headers (.h) of native modules + readable var _include_dirs: ArraySet[String] = new ArraySet[String] + + # The path of the building script + readable var _build_file: String + + # The directory where all files are generated + readable var _compdir: String + + # Return the basename of the public header file (.h) of a module + fun module_header_name(m: MMModule): String + do + if _module_include.has_key(m) then + return _module_include[m] + end + var filename = "{m.name}.{get_file_ending}.h" + _module_include[m] = filename + return filename + end + + # Cache for module_header_name + var _module_include: Map[MMModule, String] = new HashMap[MMModule, String] + + # When we are using global compilation, we generate _glob files instead + # of _sep files so that we do not corrupt separate compilation + fun get_file_ending: String do return if program.tc.global then "_glob" else "_sep" + + # Generate the shell script that build the program by calling gccx + fun generate_build_file + do + var f = new OFStream.open(_build_file) + var verbose = "" + var tc = program.tc + + if tc.verbose_level == 1 then + verbose = "-v" + else if tc.verbose_level >= 2 then + # We catch tc.verbose_level >= 2, since 3+ is not valid with gccx + verbose = "-vv" + end + + f.write("#!/bin/sh\n") + f.write("# This shell script is generated by NIT to compile the program {program.main_module.name}.\n") + f.write("CLIBDIR=\"{tc.clibdir.as(not null)}\"\n") + f.write("{tc.bindir.as(not null)}/gccx {verbose} -d {compdir} -I $CLIBDIR {include_dirs.join(" ")}") + if tc.output_file != null then + f.write(" -o {tc.output_file.as(not null)}") + else if tc.ext_prefix.is_empty then + f.write(" -o {program.main_module.name}") + else + f.write(" -o {program.main_module.name}_{tc.ext_prefix}") + end + if tc.boost then f.write(" -O") + if not tc.cc_link then f.write(" -x \"-c\"") + for l in tc.cc_libs do f.write(" -x \"-l {l}\"") + for lp in tc.cc_lib_paths do f.write(" -x \"-L {lp}\"") + for ip in tc.cc_include_paths do f.write(" -x \"-I {ip}\"") + f.write(" \"$@\" \\\n {files.join("\\\n ")}\n") + f.close + end + + # Invoke the build_file + fun run_c_compiler + do + program.tc.info("Building",1) + sys.system("sh {_build_file}") + end end # Class used to generate files. @@ -37,268 +126,167 @@ end # Note also that this class is unefficient and poorly designed thus requires love. class CompilerVisitor # Add a line in the current declaration block - meth add_decl(s: String) + fun add_decl(s: String) do - if _indent_level >= 8 then - _ctx.decls.add("\t\t" + s) - else - _ctx.decls.add(" " * _indent_level + s) - end + add_line_to(_decl_writer, s) end # Add a line in the current instr block - meth add_instr(s: String) + fun add_instr(s: String) + do + add_line_to(_writer, s) + end + + + fun add_indent(w: Writer) do if _indent_level >= 8 then - _ctx.instrs.add("\t\t" + s) + w.add("\t\t") else - _ctx.instrs.add(" " * _indent_level + s) + for i in [0.._indent_level[ do + w.add(" ") + end + end + end + + fun add_line_to(w: Writer, s: String) + do + add_indent(w) + w.add(s) + w.add("\n") + end + + # Add a assignment between a variable and an expression + fun add_assignment(v: String, s: String) + do + if v != s then + var w = _writer + add_indent(w) + w.add(v) + w.add(" = ") + w.add(s) + w.add(";\n") end end # Return a unique new number for the instance - meth new_number: Int + fun new_number: Int do var res = _number_cpt _number_cpt = res + 1 return res end # next number for new_number - attr _number_cpt: Int + var _number_cpt: Int = 0 # Add an indent level. # New decl and instr will be indented. - meth indent do _indent_level += 1 + fun indent do _indent_level += 1 # Remove an indent level. - meth unindent + fun unindent do _indent_level -= 1 if _indent_level < 0 then _indent_level = 0 end - # Return a big string containing all decl and instr - redef meth to_s - do - var out = new Array[String] - out.append(_ctx.decls) - out.append(_ctx.instrs) - out.add("") - return out.join("\n") - end + # The processed mmmodule + readable var _mmmodule: MMModule - # The current module processed - readable writable attr _module: MMSrcModule + # Where header decl are stored (public stuff) + readable writable var _header_writer: Writer - # Where instr and decl are stored - readable writable attr _ctx: CContext = new CContext + # Where current instr are stored (current function declaration) + readable writable var _writer: Writer - # The current indent lever - readable writable attr _indent_level: Int + # Where current decl are stored (current function instructions) + readable writable var _decl_writer: Writer - # The current ToolContext - readable writable attr _tc: ToolContext + # Where body instr are stored (C functions body) + readable writable var _top_writer: Writer - # Create a new CompilerVisitor based on a module - init(module: MMSrcModule) do _module = module -end + # Where body decl are stored (private C function proptypes and typedefs) + readable writable var _top_decl_writer: Writer + + # The current indent lever + readable writable var _indent_level: Int = 0 + + # The program we are compiling + readable var _program: Program -# Where instr and decl are stored for a module -# Note that this class is as badly designed as CompilerVisitor -class CContext - readable attr _decls: Array[String] = new Array[String] - readable attr _instrs: Array[String] = new Array[String] + # The cprogram associed with program + readable var _cprogram: CProgram - meth append(c: CContext) + # Create a new CompilerVisitor based on a module + init(mod: MMModule, cp: CProgram) do - _instrs.append(c.decls) - _instrs.append(c.instrs) + _mmmodule = mod + _cprogram = cp + _program = cp.program + + var w = new Writer + _header_writer = w + _decl_writer = w + w = new Writer + _writer = w + _top_writer = w + _top_decl_writer = w.sub end - - init do end end redef class MMGlobalProperty # C symbol refering a method inocation - meth meth_call: String + fun meth_call: String do return "CALL_{intro.cname}" end # C symbol refering an attribure access - meth attr_access: String + fun attr_access: String do return "ATTR_{intro.cname}" end - - # C symbol refering the color of the global property - meth color_id: String - do - return "COLOR_{intro.cname}" - end - end redef class MMGlobalClass # C symbol refering the identifier of the class - meth id_id: String + fun id_id: String do return "ID_{intro.name}" end # C symbol refering the color of the class (for subtype tests) - meth color_id: String + fun color_id: String do return "COLOR_{intro.name}" end # C symbol refering the init table position of the class (for constructor linearization) - meth init_table_pos_id: String + fun init_table_pos_id: String do return "INIT_TABLE_POS_{intro.name}" end end -redef class MMLocalClass - # Cached primitive_info result - attr _primitive_info_cache: PrimitiveInfo - - # If primitive_info result cached? - attr _primitive_info_b: Bool - - # Return the primitive information of the class. - # Return null if the class is not primitive - # FIXME: Only here since there is no universal type yet - meth primitive_info: PrimitiveInfo - do - if _primitive_info_b == true then return _primitive_info_cache - - var ctypes = once primitive_ctypes - if ctypes.has_key(name) then - _primitive_info_cache = ctypes[name] - _primitive_info_b = true - return _primitive_info_cache - end - var i = ctypes.iterator - while i.is_ok do - var n = i.key - if module.has_global_class_named(n) then - var c = module.class_by_name(n) - if cshe < c then - _primitive_info_cache = i.item - _primitive_info_b = true - return _primitive_info_cache - end - end - i.next - end - _primitive_info_b = true - return null - end - - # Static information of primitive types - private meth primitive_ctypes: HashMap[Symbol, PrimitiveInfo] - do - var res = new HashMap[Symbol, PrimitiveInfo] - var pnames = ["Int", "Char", "Bool", "Float", "NativeString", "NativeArray", "Pointer"] - var tagged = [true, true, true, false, false, false, false] - var cnames = ["bigint", "char", "int", "float", "char *", "val_t *", "void *"] - for i in [0..pnames.length[ do - var n = pnames[i].to_symbol - var pi = new PrimitiveInfo - pi.name = n - pi.tagged = tagged[i] - pi.cname = cnames[i] - res[n] = pi - end - return res - end -end - -# Information about a primitive class -class PrimitiveInfo - # The name of the class - readable writable attr _name: Symbol - - # Is the class tagged (aka not boxed) - readable writable attr _tagged: Bool - - # The corresponding c type for the primitive value - readable writable attr _cname: String - - private init do end -end - -redef class MMType - # The corresponding c type - meth cname: String - do - var pi = local_class.primitive_info - if pi == null then - return "val_t" - else - return pi.cname - end - end - - # The default c value for uninitialized types. - # Return "null" for non primitive types and something more specific for primitive types - meth default_cvalue: String - do - var pi = local_class.primitive_info - if pi != null and pi.tagged then - return "TAG_{local_class.name}(({pi.cname})0)" - else - return "NIT_NULL" - end - end - - # Box (or tag) a primitive value - # Is identity if not primitive - meth boxtype(s: String): String - do - var pi = local_class.primitive_info - if pi == null then - return s - else if pi.tagged then - return "TAG_{local_class.name}({s})" - else - return "BOX_{local_class.name}({s})" - end - end - - # Unbox (or untag) a primitive value - # Is identity if not primitive - meth unboxtype(s: String): String - do - var pi = local_class.primitive_info - if pi == null then - return s - else if pi.tagged then - return "UNTAG_{local_class.name}({s})" - else - return "UNBOX_{local_class.name}({s})" - end - end -end - redef class MMLocalProperty # Cacher result of cname - attr _cname_cache: String + var _cname_cache: nullable String # The mangled name of the method - meth cname: String + fun cname: String do - if _cname_cache == null then - _cname_cache = cmangle(module.name, local_class.name, name) + var cname = _cname_cache + if cname == null then + cname = cmangle(mmmodule.name, local_class.name, name) + _cname_cache = cname end - return _cname_cache + return cname end - # C symbol refering the color of the super call of a super property - meth color_id_for_super: String + # C macro used to get the function for the call of a super property + fun super_meth_call: String do - return "COLOR_SUPER_{cname}" + return "CALL_SUPER_{cname}" end end