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>
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
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
private import utils
import primitive_info
import program
+import compiling_writer
redef class ToolContext
readable writable var _compdir: nullable String = null
# 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
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
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
# 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
# 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
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
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
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
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)
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
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})"
--- /dev/null
+# 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
+