compile: add module compiling_writer to replace CContext
authorJean Privat <jean@pryen.org>
Fri, 29 Jan 2010 20:08:06 +0000 (15:08 -0500)
committerJean Privat <jean@pryen.org>
Mon, 15 Feb 2010 16:10:21 +0000 (11:10 -0500)
It will helps to make the code generation more flexible and more efficient.
However, this patch does not change the generated C.

Signed-off-by: Jean Privat <jean@pryen.org>

src/compiling/compiling.nit
src/compiling/compiling_base.nit
src/compiling/compiling_global.nit
src/compiling/compiling_icode.nit
src/compiling/compiling_writer.nit [new file with mode: 0644]

index f052c04..4f58fbf 100644 (file)
@@ -120,7 +120,8 @@ redef class Program
                for m in module.mhe.greaters_and_self do
                        f.write("#include \"{m.name}.{get_file_ending}.h\"\n")
                end
-               f.write(v.to_s)
+               v.header_writer.write_to_stream(f)
+               v.writer.write_to_stream(f)
                f.close
        end
 end
@@ -142,18 +143,14 @@ redef class MMModule
                f.write("#ifndef {name}{program.get_file_ending}\n")
                f.write("#define {name}{program.get_file_ending}\n")
                for m in mhe.direct_greaters do f.write("#include \"{m.name}.{program.get_file_ending}.h\"\n")
-               for s in v.ctx.decls do
-                       f.write(s)
-               end
+               v.header_writer.write_to_stream(f)
                f.write("#endif\n")
                f.close
 
                f = new OFStream.open("{tc.compdir.as(not null)}/{name}.{program.get_file_ending}.c")
                f.write("/* This C file is generated by NIT to compile module {name}. */\n")
                f.write("#include \"{name}.{program.get_file_ending}.h\"\n")
-               for s in v.ctx.instrs do
-                       f.write(s)
-               end
+               v.top_writer.write_to_stream(f)
                f.close
        end
 end
index a1f2f2d..9745021 100644 (file)
@@ -21,6 +21,7 @@ import mmloader
 private import utils
 import primitive_info
 import program
+import compiling_writer
 
 redef class ToolContext
        readable writable var _compdir: nullable String = null
@@ -41,43 +42,49 @@ end
 # Note also that this class is unefficient and poorly designed thus requires love.
 class CompilerVisitor
        # Add a line in the current declaration block
-       fun add_decl(s: String...)
+       fun add_decl(s: String)
        do
-               add_line_to(_ctx.decls, s)
+               add_line_to(_decl_writer, s)
        end
 
        # Add a line in the current instr block
-       fun add_instr(s: String...)
+       fun add_instr(s: String)
        do
-               add_line_to(_ctx.instrs, s)
+               add_line_to(_writer, s)
        end
 
-       fun add_line_to(a: Array[String], s: Array[String])
+
+       fun add_indent(w: Writer)
        do
                if _indent_level >= 8 then
-                       a.add("\t\t")
+                       w.add("\t\t")
                else
                        for i in [0.._indent_level[ do
-                               a.add("  ")
+                               w.add("  ")
                        end
                end
-               for i in s do
-                       a.add(i)
-               end
-               a.add("\n")
+       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
-                       add_instr(v, " = ", s, ";")
+                       var w = _writer
+                       add_indent(w)
+                       w.add(v)
+                       w.add(" = ")
+                       w.add(s)
+                       w.add(";\n")
                end
        end
 
-       # C outputs written outside the current C function.
-       readable writable var _out_contexts: Array[CContext] = new Array[CContext]
-
        # Return a unique new number for the instance
        fun new_number: Int
        do
@@ -99,20 +106,23 @@ class CompilerVisitor
                if _indent_level < 0 then _indent_level = 0
        end
 
-       # Return a big string containing all decl and instr
-       redef fun to_s
-       do
-               var out = new Array[String]
-               out.append(_ctx.decls)
-               out.append(_ctx.instrs)
-               return out.to_s
-       end
-
        # The processed module
        readable var _module: MMModule
 
-       # Where instr and decl are stored
-       readable writable var _ctx: CContext = new CContext
+       # Where header decl are stored (public stuff)
+       readable writable var _header_writer: Writer
+
+       # Where current instr are stored (current function declaration)
+       readable writable var _writer: Writer
+
+       # Where current decl are stored (current function instructions)
+       readable writable var _decl_writer: Writer
+
+       # Where body instr are stored (C functions body)
+       readable writable var _top_writer: Writer
+
+       # 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
@@ -125,28 +135,15 @@ class CompilerVisitor
        do
                _module = module
                _program = p
-       end
-end
 
-# Where instr and decl are stored for a module
-# Note that this class is as badly designed as CompilerVisitor
-class CContext
-       readable var _decls: Array[String] = new Array[String] 
-       readable var _instrs: Array[String] = new Array[String]
-
-       fun append(c: CContext)
-       do
-               _instrs.append(c.decls)
-               _instrs.append(c.instrs)
+               var w = new Writer
+               _header_writer = w
+               _decl_writer = w
+               w = new Writer
+               _writer = w
+               _top_writer = w
+               _top_decl_writer = w.sub
        end
-       
-       fun merge(c: CContext)
-       do
-               _decls.append(c.decls)
-               _instrs.append(c.instrs)
-       end
-
-       init do end
 end
 
 redef class MMGlobalProperty
index cab99dc..ffb6708 100644 (file)
@@ -387,11 +387,10 @@ redef class MMLocalClass
                                # Generate INIT_ATTRIBUTES routine
                                var cname = "INIT_ATTRIBUTES__{name}"
                                var args = init_var_iroutine.compile_signature_to_c(v, cname, "init var of {name}", null, null)
-                               var ctx_old = v.ctx
-                               v.ctx = new CContext
+                               var decl_writer_old = v.decl_writer
+                               v.decl_writer = v.writer.sub
                                init_var_iroutine.compile_to_c(v, cname, args)
-                               ctx_old.append(v.ctx)
-                               v.ctx = ctx_old
+                               v.decl_writer = decl_writer_old
                                v.unindent
                                v.add_instr("}")
                        end
@@ -414,11 +413,10 @@ redef class MMLocalClass
                                # Compile CHECKNAME
                                var cname = "CHECKNEW_{name}"
                                var args = checknew_iroutine.compile_signature_to_c(v, cname, "check new {name}", null, null)
-                               var ctx_old = v.ctx
-                               v.ctx = new CContext
+                               var decl_writer_old = v.decl_writer
+                               v.decl_writer = v.writer.sub
                                checknew_iroutine.compile_to_c(v, cname, args)
-                               ctx_old.append(v.ctx)
-                               v.ctx = ctx_old
+                               v.decl_writer = decl_writer_old
                                v.unindent
                                v.add_instr("}")
                        end
@@ -434,13 +432,12 @@ redef class MMLocalClass
 
                                var cname = "NEW_{self}_{p.global.intro.cname}"
                                var new_args = new_instance_iroutine[p].compile_signature_to_c(v, cname, "new {self} {p.full_name}", null, null)
-                               var ctx_old = v.ctx
-                               v.ctx = new CContext
+                               var decl_writer_old = v.decl_writer
+                               v.decl_writer = v.writer.sub
                                v.add_instr(init_table_decl)
                                var e = new_instance_iroutine[p].compile_to_c(v, cname, new_args).as(not null)
                                v.add_instr("return {e};")
-                               ctx_old.append(v.ctx)
-                               v.ctx = ctx_old
+                               v.decl_writer = decl_writer_old
                                v.unindent
                                v.add_instr("}")
                        end
@@ -470,10 +467,10 @@ redef class MMMethod
                var more_params: nullable String = null
                if global.is_init then more_params = "int* init_table"
                var args = ir.compile_signature_to_c(v, cname, full_name, null, more_params)
-               var ctx_old = v.ctx
-               v.ctx = new CContext
-
-               v.out_contexts.clear
+               var writer_old = v.writer
+               v.writer = v.writer.sub
+               var decl_writer_old = v.decl_writer
+               v.decl_writer = v.writer.sub
 
                var itpos: nullable String = null
                if global.is_init then
@@ -490,15 +487,13 @@ redef class MMMethod
                if s == null then
                        v.add_instr("return;")
                else
-                       v.add_instr("return ", s, ";")
+                       v.add_instr("return {s};")
                end
-
-               ctx_old.append(v.ctx)
-               v.ctx = ctx_old
                v.unindent
                v.add_instr("}")
 
-               for ctx in v.out_contexts do v.ctx.merge(ctx)
+               v.writer = writer_old
+               v.decl_writer = decl_writer_old
        end
 end
 
index 5374ac8..82cf93c 100644 (file)
@@ -163,7 +163,13 @@ class I2CCompilerVisitor
        do
                var l = _next_location
                if l != null then
-                       visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */")
+                       var w = visitor.writer
+                       visitor.add_indent(w)
+                       w.add("/* ")
+                       w.add(l.file)
+                       w.add(":")
+                       w.add(l.line_start.to_s)
+                       w.add(" */\n")
                        _next_location = null
                end
                visitor.add_instr(s)
@@ -252,10 +258,10 @@ redef class IRoutine
                else
                        p = cparams.join(", ")
                end
-               if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"")
-               v.add_decl(r, " ", cname, "(", p, ");")
-               v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");")
-               v.add_instr(r, " ", cname, "(", p, ")\{")
+               if human_name != null then v.add_decl("#define LOCATE_{cname} \"{human_name}\"")
+               v.add_decl("{r} {cname}({p});")
+               v.add_decl("typedef {r} (*{cname}_t)({p});")
+               v.add_instr("{r} {cname}({p})\{")
                v.indent
                return cargs
        end
@@ -817,28 +823,28 @@ redef class IClosureDef
                v.local_labels = new HashSet[ISeq]
 
                # We are now in a new C context
-               var ctx_old = cv.ctx
-               cv.ctx = new CContext
-               cv.out_contexts.add(cv.ctx)
+               var decl_writer_old = cv.decl_writer
+               var writer_old = cv.writer
+               cv.writer = cv.top_writer.sub
+               cv.decl_writer = cv.header_writer.sub
 
                # Generate the C function
                var cname = "OC_{v.basecname}_{v.new_number}"
                var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null)
-               var ctx_old2 = cv.ctx
-               cv.ctx = new CContext
+               cv.decl_writer = cv.writer.sub
+
                var s = compile_inside_to_c(v, args)
                if s == null then
                        v.add_instr("return;")
                else
                        v.add_instr("return {s};")
                end
-               ctx_old2.append(cv.ctx)
-               cv.ctx = ctx_old2
                v.unindent
                v.add_instr("}")
 
                # Restore things
-               cv.ctx = ctx_old
+               cv.writer = writer_old
+               cv.decl_writer = decl_writer_old
                v.closure = cfc_old
                v.local_labels = lls_old
                return "((fun_t){cname})"
diff --git a/src/compiling/compiling_writer.nit b/src/compiling/compiling_writer.nit
new file mode 100644 (file)
index 0000000..8e2294a
--- /dev/null
@@ -0,0 +1,152 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2010 Jean Privat <jean@pryen.org>
+#
+# 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.
+
+# Helps to generate complex strings.
+# Can be used to simplify complex file generation where text addition is not only done at the end
+package compiling_writer
+
+# A writer is used to store a sequence of strings and sub-writers
+class Writer
+       # Add a new string at the end of the writer
+       fun add(s: String): Writer
+       do
+               assert not is_frozen
+               var c = _last_string
+               var c2 = new WriterStrings(s)
+               if c == null then
+                       internal_append(c2)
+               else
+                       c._next = c2
+               end
+               _last_string = c2
+               return self
+       end
+
+       # Add each string of the array but separate them
+       fun add_all(a: Array[String], separator: String): Writer
+       do
+               assert not is_frozen
+               var first = true
+               for s in a do
+                       if first then first = false else add(separator)
+                       add(s)
+               end
+               return self
+       end
+
+       var _first_sub_writer: nullable WriterNode = null
+       var _last_sub_writer: nullable WriterNode = null
+
+       # Last string added. Implies that _last_sub_writer isa WriterStrings
+       var _last_string: nullable WriterStrings = null
+
+       # Insert an other Writer at the end of the writer
+       fun append(c: Writer): Writer
+       do
+               assert not is_frozen
+               internal_append(new WriterCoreNode(c))
+               _last_string = null # next add will create a new WriterStrings after c
+               return self
+       end
+
+       # Insert a writer as a sub-one
+       private fun internal_append(c: WriterNode)
+       do
+               if _first_sub_writer == null then _first_sub_writer = c
+               var l = _last_sub_writer
+               if l != null then l._next_writer = c
+               _last_sub_writer = c
+       end
+
+       # Create a sub-writer that can be used as a new string insertion point
+       fun sub: Writer
+       do
+               var c = new Writer
+               append(c)
+               return c
+       end
+
+       var _is_writing: Bool = false
+
+       # Write all strings (including nested ones) to a stream
+       fun write_to_stream(s: OStream)
+       do
+               assert not _is_writing
+               _is_writing = true
+               var cur = _first_sub_writer
+               while cur != null do
+                       cur.internal_write_to_stream(s)
+                       cur = cur._next_writer
+               end
+               _is_writing = false
+       end
+
+       # Return true if the string writer is frozen
+       readable var _is_frozen: Bool = false
+
+       # Disable funter writer modification: nor add or append are allowed
+       fun freeze
+       do
+               if is_frozen then return
+               _is_frozen = true
+       end
+
+       init do end
+end
+
+# Simple linked list of Writers contents
+private abstract class WriterNode
+       # The next writer in the list
+       var _next_writer: nullable WriterNode = null
+
+       # Write all strings (including nested ones) to a stream
+       fun internal_write_to_stream(s: OStream) is abstract
+end
+
+# A writer node that contains a full writer
+private class WriterCoreNode
+special WriterNode
+       var _writer: Writer
+
+       redef fun internal_write_to_stream(s) do _writer.write_to_stream(s)
+
+       init(w: Writer) do _writer = w
+end
+
+# A simple writer node that contains only strings
+private class WriterStrings
+special WriterNode
+       # The first string
+       var _string: String
+
+       # The next strings
+       var _next: nullable WriterStrings = null
+
+       init(s: String)
+       do
+               _string = s
+       end
+
+       redef fun internal_write_to_stream(s)
+       do
+               var cur: nullable WriterStrings = self
+               while cur != null do
+                       s.write(cur._string)
+                       cur = cur._next
+               end
+       end
+end
+