<commit_before>/* valacodewriter.vala
 *
 * Copyright (C) 2006-2010  <NAME>
 * Copyright (C) 2006-2008  <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	<NAME> <<EMAIL>>
 *	<NAME> <<EMAIL>>
 */


/**
 * Code visitor generating Vala API file for the public interface.
 */
public class Vala.CodeWriter : CodeVisitor {
	private CodeContext context;
	
	FileStream stream;
	
	int indent;
	/* at begin of line */
	bool bol = true;

	Scope current_scope;

	CodeWriterType type;

	string? override_header = null;
	string? header_to_override = null;

	public CodeWriter (CodeWriterType type = CodeWriterType.EXTERNAL) {
		this.type = type;
	}

	/**
	 * Allows overriding of a specific cheader in the output
	 * @param original orignal cheader to override
	 * @param replacement cheader to replace original with
	 */
	public void set_cheader_override (string original, string replacement)
	{
		header_to_override = original;
		override_header = replacement;
	}

	/**
	 * Writes the public interface of the specified code context into the
	 * specified file.
	 *
	 * @param context  a code context
	 * @param filename a relative or absolute filename
	 */
	public void write_file (CodeContext context, string filename) {
		var file_exists = FileUtils.test (filename, FileTest.EXISTS);
		var temp_filename = filename + ".valatmp";
		this.context = context;

		if (file_exists) {
			stream = FileStream.open (temp_filename, "w");
		} else {
			stream = FileStream.open (filename, "w");
		}

		if (stream == null) {
			Report.error (null, "unable to open `%s' for writing".printf (filename));
			return;
		}

		var header = context.version_header ?
			"/* %s generated by %s %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname (), Config.BUILD_VERSION) :
			"/* %s generated by %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname ());
		write_string (header);
		write_newline ();
		write_newline ();

		current_scope = context.root.scope;

		context.accept (this);

		current_scope = null;

		stream = null;

		if (file_exists) {
			var changed = true;

			try {
				var old_file = new MappedFile (filename, false);
				var new_file = new MappedFile (temp_filename, false);
				var len = old_file.get_length ();
				if (len == new_file.get_length ()) {
					if (Memory.cmp (old_file.get_contents (), new_file.get_contents (), len) == 0) {
						changed = false;
					}
				}
				old_file = null;
				new_file = null;
			} catch (FileError e) {
				// assume changed if mmap comparison doesn't work
			}

			if (changed) {
				FileUtils.rename (temp_filename, filename);
			} else {
				FileUtils.unlink (temp_filename);
			}
		}

	}

	public override void visit_using_directive (UsingDirective ns) {
		if (type == CodeWriterType.FAST) {
			write_string ("using %s;\n".printf (ns.namespace_symbol.name));
		}
	}

	public override void visit_namespace (Namespace ns) {
		if (ns.external_package) {
			return;
		}

		if (ns.name == null)  {
			ns.accept_children (this);
			return;
		}

		write_indent ();
		write_string ("[CCode (cprefix = \"%s\", lower_case_cprefix = \"%s\"".printf (ns.get_cprefix (), ns.get_lower_case_cprefix ()));

		if (ns.source_reference != null && ns.parent_symbol == context.root) {
			// Set GIR information only for the main namespace of the file.
			if (ns.source_reference.file.gir_namespace != null) {
				write_string (", ");
				write_string ("gir_namespace = \"%s\"".printf (ns.source_reference.file.gir_namespace));
			}
			if (ns.source_reference.file.gir_version != null) {
				write_string(", ");
				write_string ("gir_version = \"%s\"".printf (ns.source_reference.file.gir_version));
			}
		}

		write_string (")]");
		write_newline ();

		write_attributes (ns);

		write_indent ();
		write_string ("namespace ");
		write_identifier (ns.name);
		write_begin_block ();

		current_scope = ns.scope;

		visit_sorted (ns.get_namespaces ());
		visit_sorted (ns.get_classes ());
		visit_sorted (ns.get_interfaces ());
		visit_sorted (ns.get_structs ());
		visit_sorted (ns.get_enums ());
		visit_sorted (ns.get_error_domains ());
		visit_sorted (ns.get_delegates ());
		visit_sorted (ns.get_fields ());
		visit_sorted (ns.get_constants ());
		visit_sorted (ns.get_methods ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	private string get_cheaders (Symbol cl) {
		bool first = true;
		string cheaders = "";
		if (type != CodeWriterType.FAST) {
			foreach (string cheader in cl.get_cheader_filenames ()) {
				if (header_to_override != null &&
				    cheader == header_to_override) {
					cheader = override_header;
				}
				if (first) {
					cheaders = cheader;
					first = false;
				} else {
					cheaders = "%s,%s".printf (cheaders, cheader);
				}
			}
		}
		return cheaders;
	}

	private void emit_deprecated_attribute (Symbol symbol) {
		if (symbol.deprecated) {
			write_indent ();
			write_string ("[Deprecated");
			var since = symbol.deprecated_since;
			var replacement = symbol.replacement;

			if (since != null || replacement != null) {
				write_string (" (");
				if (since != null) {
					write_string ("since = \"%s\"".printf (since));
				}
				if (since != null && replacement != null) {
					write_string (", ");
				}
				if (replacement != null) {
					write_string ("replacement = \"%s\"".printf (replacement));
				}
				write_string (")");
			}
			write_string ("]");
		}
	}

	private void emit_experimental_attribute (Symbol symbol) {
		if (symbol.experimental) {
			write_indent ();
			write_string ("[Experimental]");
			write_newline ();
		}
	}

	public override void visit_class (Class cl) {
		if (cl.external_package) {
			return;
		}

		if (!check_accessibility (cl)) {
			return;
		}

		if (cl.is_compact) {
			write_indent ();
			write_string ("[Compact]");
			write_newline ();
		}

		if (cl.is_immutable) {
			write_indent ();
			write_string ("[Immutable]");
			write_newline ();
		}

		emit_deprecated_attribute (cl);
		emit_experimental_attribute (cl);

		write_indent ();
		
		write_string ("[CCode (");

		if (cl.is_reference_counting () && type != CodeWriterType.FAST) {
			if (cl.base_class == null || cl.base_class.get_ref_function () == null || cl.base_class.get_ref_function () != cl.get_ref_function ()) {
				write_string ("ref_function = \"%s\", ".printf (cl.get_ref_function ()));
				if (cl.ref_function_void) {
					write_string ("ref_function_void = true, ");
				}
			}
			if (cl.base_class == null || cl.base_class.get_unref_function () == null || cl.base_class.get_unref_function () != cl.get_unref_function ()) {
				write_string ("unref_function = \"%s\", ".printf (cl.get_unref_function ()));
			}
		} else {
			if (cl.get_dup_function () != null) {
				write_string ("copy_function = \"%s\", ".printf (cl.get_dup_function ()));
			}
			if (cl.get_free_function () != cl.get_default_free_function ()) {
				write_string ("free_function = \"%s\", ".printf (cl.get_free_function ()));
			}
		}

		if (cl.get_cname () != cl.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (cl.get_cname ()));
		}
		if (cl.const_cname != null) {
			write_string ("const_cname = \"%s\", ".printf (cl.const_cname));
		}

		if (cl.type_check_function != null) {
			write_string ("type_check_function = \"%s\", ".printf (cl.type_check_function ));
		}

		if (cl.get_type_id () != cl.get_default_type_id ()) {
			write_string ("type_id = \"%s\", ".printf (cl.get_type_id ()));
		}

		if (cl.get_param_spec_function () != cl.get_default_param_spec_function ()) {
			write_string ("param_spec_function = \"%s\", ".printf (cl.get_param_spec_function ()));
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl)));
		write_newline ();

		write_attributes (cl);
		
		write_indent ();
		write_accessibility (cl);
		if (cl.is_abstract) {
			write_string ("abstract ");
		}
		write_string ("class ");
		write_identifier (cl.name);

		var type_params = cl.get_type_parameters ();
		if (type_params.size > 0) {
			write_string ("<");
			bool first = true;
			foreach (TypeParameter type_param in type_params) {
				if (first) {
					first = false;
				} else {
					write_string (",");
				}
				write_identifier (type_param.name);
			}
			write_string (">");
		}

		var base_types = cl.get_base_types ();
		if (base_types.size > 0) {
			write_string (" : ");
		
			bool first = true;
			foreach (DataType base_type in base_types) {
				if (!first) {
					write_string (", ");
				} else {
					first = false;
				}
				write_type (base_type);
			}
		}
		write_begin_block ();

		current_scope = cl.scope;

		visit_sorted (cl.get_classes ());
		visit_sorted (cl.get_structs ());
		visit_sorted (cl.get_enums ());
		visit_sorted (cl.get_delegates ());
		visit_sorted (cl.get_fields ());
		visit_sorted (cl.get_constants ());
		visit_sorted (cl.get_methods ());
		visit_sorted (cl.get_properties ());
		visit_sorted (cl.get_signals ());

		if (cl.constructor != null) {
			cl.constructor.accept (this);
		}

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	void visit_sorted (List<Symbol> symbols) {
		if (type != CodeWriterType.EXTERNAL) {
			// order of virtual methods matters for fast vapis
			foreach (Symbol sym in symbols) {
				sym.accept (this);
			}
			return;
		}

		var sorted_symbols = new ArrayList<Symbol> ();
		foreach (Symbol sym in symbols) {
			int left = 0;
			int right = sorted_symbols.size - 1;
			if (left > right || sym.name < sorted_symbols[left].name) {
				sorted_symbols.insert (0, sym);
			} else if (sym.name > sorted_symbols[right].name) {
				sorted_symbols.add (sym);
			} else {
				while (right - left > 1) {
					int i = (right + left) / 2;
					if (sym.name > sorted_symbols[i].name) {
						left = i;
					} else {
						right = i;
					}
				}
				sorted_symbols.insert (left + 1, sym);
			}
		}
		foreach (Symbol sym in sorted_symbols) {
			sym.accept (this);
		}
	}

	public override void visit_struct (Struct st) {
		if (st.external_package) {
			return;
		}

		if (!check_accessibility (st)) {
			return;
		}
		
		if (st.is_immutable) {
			write_indent ();
			write_string ("[Immutable]");
			write_newline ();
		}

		emit_deprecated_attribute (st);
		emit_experimental_attribute (st);

		write_indent ();

		write_string ("[CCode (");

		if (st.get_cname () != st.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (st.get_cname ()));
		}

		if (!st.has_type_id) {
			write_string ("has_type_id = false, ");
		} else if (!st.is_simple_type () && st.get_type_id () != "G_TYPE_POINTER") {
			write_string ("type_id = \"%s\", ".printf (st.get_type_id ()));
		}

		if (!st.has_copy_function) {
			write_string ("has_copy_function = false, ");
		}

		if (!st.has_destroy_function) {
			write_string ("has_destroy_function = false, ");
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st)));
		write_newline ();

		if (st.is_simple_type ()) {
			write_indent ();
			write_string ("[SimpleType]");
			write_newline ();
		}

		if (st.is_integer_type ()) {
			write_indent ();
			write_string ("[IntegerType (rank = %d)]".printf (st.get_rank ()));
			write_newline ();
		}

		if (st.is_floating_type ()) {
			write_indent ();
			write_string ("[FloatingType (rank = %d)]".printf (st.get_rank ()));
			write_newline ();
		}

		write_attributes (st);

		write_indent ();
		write_accessibility (st);
		write_string ("struct ");
		write_identifier (st.name);

		if (st.base_type != null) {
			write_string (" : ");
			write_type (st.base_type);
		}

		write_begin_block ();

		current_scope = st.scope;

		foreach (Field field in st.get_fields ()) {
			field.accept (this);
		}
		visit_sorted (st.get_constants ());
		visit_sorted (st.get_methods ());
		visit_sorted (st.get_properties ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_interface (Interface iface) {
		if (iface.external_package) {
			return;
		}

		if (!check_accessibility (iface)) {
			return;
		}

		emit_deprecated_attribute (iface);
		emit_experimental_attribute (iface);

		write_indent ();

		write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface)));
		if (iface.get_lower_case_csuffix () != iface.get_default_lower_case_csuffix ())
			write_string (", lower_case_csuffix = \"%s\"".printf (iface.get_lower_case_csuffix ()));
		if (iface.get_type_cname () != iface.get_default_type_cname ())
			write_string (", type_cname = \"%s\"".printf (iface.get_type_cname ()));
		if (iface.get_type_id () != iface.get_default_type_id ())
			write_string (", type_id = \"%s\"".printf (iface.get_type_id ()));

		write_string (")]");
		write_newline ();

		write_attributes (iface);

		write_indent ();
		write_accessibility (iface);
		write_string ("interface ");
		write_identifier (iface.name);

		var type_params = iface.get_type_parameters ();
		if (type_params.size > 0) {
			write_string ("<");
			bool first = true;
			foreach (TypeParameter type_param in type_params) {
				if (first) {
					first = false;
				} else {
					write_string (",");
				}
				write_identifier (type_param.name);
			}
			write_string (">");
		}

		var prerequisites = iface.get_prerequisites ();
		if (prerequisites.size > 0) {
			write_string (" : ");
		
			bool first = true;
			foreach (DataType prerequisite in prerequisites) {
				if (!first) {
					write_string (", ");
				} else {
					first = false;
				}
				write_type (prerequisite);
			}
		}
		write_begin_block ();

		current_scope = iface.scope;

		visit_sorted (iface.get_classes ());
		visit_sorted (iface.get_structs ());
		visit_sorted (iface.get_enums ());
		visit_sorted (iface.get_delegates ());
		visit_sorted (iface.get_fields ());
		visit_sorted (iface.get_constants ());
		visit_sorted (iface.get_methods ());
		visit_sorted (iface.get_properties ());
		visit_sorted (iface.get_signals ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_enum (Enum en) {
		if (en.external_package) {
			return;
		}

		if (!check_accessibility (en)) {
			return;
		}

		emit_deprecated_attribute (en);
		emit_experimental_attribute (en);

		write_indent ();

		write_string ("[CCode (cprefix = \"%s\", ".printf (en.get_cprefix ()));

		if (!en.has_type_id) {
			write_string ("has_type_id = false, ");
		}

		if (en.get_cname () != en.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (en.get_cname ()));
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en)));

		if (en.is_flags) {
			write_indent ();
			write_string ("[Flags]");
		}

		write_attributes (en);

		write_indent ();
		write_accessibility (en);
		write_string ("enum ");
		write_identifier (en.name);
		write_begin_block ();

		bool first = true;
		foreach (EnumValue ev in en.get_values ()) {
			if (first) {
				first = false;
			} else {
				write_string (",");
				write_newline ();
			}

			if (ev.get_cname () != ev.get_default_cname ()) {
				write_indent ();
				write_string ("[CCode (cname = \"%s\")]".printf (ev.get_cname ()));
			}
			write_indent ();
			write_identifier (ev.name);

			if (type == CodeWriterType.FAST && ev.value != null) {
				write_string(" = ");
				ev.value.accept (this);
			}
		}

		if (!first) {
			if (en.get_methods ().size > 0 || en.get_constants ().size > 0) {
				write_string (";");
			}
			write_newline ();
		}

		current_scope = en.scope;
		foreach (Method m in en.get_methods ()) {
			m.accept (this);
		}
		foreach (Constant c in en.get_constants ()) {
			c.accept (this);
		}
		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_error_domain (ErrorDomain edomain) {
		if (edomain.external_package) {
			return;
		}

		if (!check_accessibility (edomain)) {
			return;
		}

		emit_deprecated_attribute (edomain);
		emit_experimental_attribute (edomain);

		write_indent ();

		write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain.get_cprefix (), get_cheaders(edomain)));

		write_attributes (edomain);

		write_indent ();
		write_accessibility (edomain);
		write_string ("errordomain ");
		write_identifier (edomain.name);
		write_begin_block ();

		edomain.accept_children (this);

		write_end_block ();
		write_newline ();
	}

	public override void visit_error_code (ErrorCode ecode) {
		if (ecode.get_cname () != ecode.get_default_cname ()) {
			write_indent ();
			write_string ("[CCode (cname = \"%s\")]".printf (ecode.get_cname ()));
		}
		write_indent ();
		write_identifier (ecode.name);
		write_string (",");
		write_newline ();
	}

	public override void visit_constant (Constant c) {
		if (c.external_package) {
			return;
		}

		if (!check_accessibility (c)) {
			return;
		}

		emit_deprecated_attribute (c);
		emit_experimental_attribute (c);

		bool custom_cname = (c.get_cname () != c.get_default_cname ());
		bool custom_cheaders = (c.parent_symbol is Namespace);<commit_msg>codewriter: Fix writing methods inside error domains<commit_after>/* valacodewriter.vala
 *
 * Copyright (C) 2006-2010  <NAME>
 * Copyright (C) 2006-2008  <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	<NAME> <<EMAIL>>
 *	<NAME> <<EMAIL>>
 */


/**
 * Code visitor generating Vala API file for the public interface.
 */
public class Vala.CodeWriter : CodeVisitor {
	private CodeContext context;
	
	FileStream stream;
	
	int indent;
	/* at begin of line */
	bool bol = true;

	Scope current_scope;

	CodeWriterType type;

	string? override_header = null;
	string? header_to_override = null;

	public CodeWriter (CodeWriterType type = CodeWriterType.EXTERNAL) {
		this.type = type;
	}

	/**
	 * Allows overriding of a specific cheader in the output
	 * @param original orignal cheader to override
	 * @param replacement cheader to replace original with
	 */
	public void set_cheader_override (string original, string replacement)
	{
		header_to_override = original;
		override_header = replacement;
	}

	/**
	 * Writes the public interface of the specified code context into the
	 * specified file.
	 *
	 * @param context  a code context
	 * @param filename a relative or absolute filename
	 */
	public void write_file (CodeContext context, string filename) {
		var file_exists = FileUtils.test (filename, FileTest.EXISTS);
		var temp_filename = filename + ".valatmp";
		this.context = context;

		if (file_exists) {
			stream = FileStream.open (temp_filename, "w");
		} else {
			stream = FileStream.open (filename, "w");
		}

		if (stream == null) {
			Report.error (null, "unable to open `%s' for writing".printf (filename));
			return;
		}

		var header = context.version_header ?
			"/* %s generated by %s %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname (), Config.BUILD_VERSION) :
			"/* %s generated by %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname ());
		write_string (header);
		write_newline ();
		write_newline ();

		current_scope = context.root.scope;

		context.accept (this);

		current_scope = null;

		stream = null;

		if (file_exists) {
			var changed = true;

			try {
				var old_file = new MappedFile (filename, false);
				var new_file = new MappedFile (temp_filename, false);
				var len = old_file.get_length ();
				if (len == new_file.get_length ()) {
					if (Memory.cmp (old_file.get_contents (), new_file.get_contents (), len) == 0) {
						changed = false;
					}
				}
				old_file = null;
				new_file = null;
			} catch (FileError e) {
				// assume changed if mmap comparison doesn't work
			}

			if (changed) {
				FileUtils.rename (temp_filename, filename);
			} else {
				FileUtils.unlink (temp_filename);
			}
		}

	}

	public override void visit_using_directive (UsingDirective ns) {
		if (type == CodeWriterType.FAST) {
			write_string ("using %s;\n".printf (ns.namespace_symbol.name));
		}
	}

	public override void visit_namespace (Namespace ns) {
		if (ns.external_package) {
			return;
		}

		if (ns.name == null)  {
			ns.accept_children (this);
			return;
		}

		write_indent ();
		write_string ("[CCode (cprefix = \"%s\", lower_case_cprefix = \"%s\"".printf (ns.get_cprefix (), ns.get_lower_case_cprefix ()));

		if (ns.source_reference != null && ns.parent_symbol == context.root) {
			// Set GIR information only for the main namespace of the file.
			if (ns.source_reference.file.gir_namespace != null) {
				write_string (", ");
				write_string ("gir_namespace = \"%s\"".printf (ns.source_reference.file.gir_namespace));
			}
			if (ns.source_reference.file.gir_version != null) {
				write_string(", ");
				write_string ("gir_version = \"%s\"".printf (ns.source_reference.file.gir_version));
			}
		}

		write_string (")]");
		write_newline ();

		write_attributes (ns);

		write_indent ();
		write_string ("namespace ");
		write_identifier (ns.name);
		write_begin_block ();

		current_scope = ns.scope;

		visit_sorted (ns.get_namespaces ());
		visit_sorted (ns.get_classes ());
		visit_sorted (ns.get_interfaces ());
		visit_sorted (ns.get_structs ());
		visit_sorted (ns.get_enums ());
		visit_sorted (ns.get_error_domains ());
		visit_sorted (ns.get_delegates ());
		visit_sorted (ns.get_fields ());
		visit_sorted (ns.get_constants ());
		visit_sorted (ns.get_methods ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	private string get_cheaders (Symbol cl) {
		bool first = true;
		string cheaders = "";
		if (type != CodeWriterType.FAST) {
			foreach (string cheader in cl.get_cheader_filenames ()) {
				if (header_to_override != null &&
				    cheader == header_to_override) {
					cheader = override_header;
				}
				if (first) {
					cheaders = cheader;
					first = false;
				} else {
					cheaders = "%s,%s".printf (cheaders, cheader);
				}
			}
		}
		return cheaders;
	}

	private void emit_deprecated_attribute (Symbol symbol) {
		if (symbol.deprecated) {
			write_indent ();
			write_string ("[Deprecated");
			var since = symbol.deprecated_since;
			var replacement = symbol.replacement;

			if (since != null || replacement != null) {
				write_string (" (");
				if (since != null) {
					write_string ("since = \"%s\"".printf (since));
				}
				if (since != null && replacement != null) {
					write_string (", ");
				}
				if (replacement != null) {
					write_string ("replacement = \"%s\"".printf (replacement));
				}
				write_string (")");
			}
			write_string ("]");
		}
	}

	private void emit_experimental_attribute (Symbol symbol) {
		if (symbol.experimental) {
			write_indent ();
			write_string ("[Experimental]");
			write_newline ();
		}
	}

	public override void visit_class (Class cl) {
		if (cl.external_package) {
			return;
		}

		if (!check_accessibility (cl)) {
			return;
		}

		if (cl.is_compact) {
			write_indent ();
			write_string ("[Compact]");
			write_newline ();
		}

		if (cl.is_immutable) {
			write_indent ();
			write_string ("[Immutable]");
			write_newline ();
		}

		emit_deprecated_attribute (cl);
		emit_experimental_attribute (cl);

		write_indent ();
		
		write_string ("[CCode (");

		if (cl.is_reference_counting () && type != CodeWriterType.FAST) {
			if (cl.base_class == null || cl.base_class.get_ref_function () == null || cl.base_class.get_ref_function () != cl.get_ref_function ()) {
				write_string ("ref_function = \"%s\", ".printf (cl.get_ref_function ()));
				if (cl.ref_function_void) {
					write_string ("ref_function_void = true, ");
				}
			}
			if (cl.base_class == null || cl.base_class.get_unref_function () == null || cl.base_class.get_unref_function () != cl.get_unref_function ()) {
				write_string ("unref_function = \"%s\", ".printf (cl.get_unref_function ()));
			}
		} else {
			if (cl.get_dup_function () != null) {
				write_string ("copy_function = \"%s\", ".printf (cl.get_dup_function ()));
			}
			if (cl.get_free_function () != cl.get_default_free_function ()) {
				write_string ("free_function = \"%s\", ".printf (cl.get_free_function ()));
			}
		}

		if (cl.get_cname () != cl.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (cl.get_cname ()));
		}
		if (cl.const_cname != null) {
			write_string ("const_cname = \"%s\", ".printf (cl.const_cname));
		}

		if (cl.type_check_function != null) {
			write_string ("type_check_function = \"%s\", ".printf (cl.type_check_function ));
		}

		if (cl.get_type_id () != cl.get_default_type_id ()) {
			write_string ("type_id = \"%s\", ".printf (cl.get_type_id ()));
		}

		if (cl.get_param_spec_function () != cl.get_default_param_spec_function ()) {
			write_string ("param_spec_function = \"%s\", ".printf (cl.get_param_spec_function ()));
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl)));
		write_newline ();

		write_attributes (cl);
		
		write_indent ();
		write_accessibility (cl);
		if (cl.is_abstract) {
			write_string ("abstract ");
		}
		write_string ("class ");
		write_identifier (cl.name);

		var type_params = cl.get_type_parameters ();
		if (type_params.size > 0) {
			write_string ("<");
			bool first = true;
			foreach (TypeParameter type_param in type_params) {
				if (first) {
					first = false;
				} else {
					write_string (",");
				}
				write_identifier (type_param.name);
			}
			write_string (">");
		}

		var base_types = cl.get_base_types ();
		if (base_types.size > 0) {
			write_string (" : ");
		
			bool first = true;
			foreach (DataType base_type in base_types) {
				if (!first) {
					write_string (", ");
				} else {
					first = false;
				}
				write_type (base_type);
			}
		}
		write_begin_block ();

		current_scope = cl.scope;

		visit_sorted (cl.get_classes ());
		visit_sorted (cl.get_structs ());
		visit_sorted (cl.get_enums ());
		visit_sorted (cl.get_delegates ());
		visit_sorted (cl.get_fields ());
		visit_sorted (cl.get_constants ());
		visit_sorted (cl.get_methods ());
		visit_sorted (cl.get_properties ());
		visit_sorted (cl.get_signals ());

		if (cl.constructor != null) {
			cl.constructor.accept (this);
		}

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	void visit_sorted (List<Symbol> symbols) {
		if (type != CodeWriterType.EXTERNAL) {
			// order of virtual methods matters for fast vapis
			foreach (Symbol sym in symbols) {
				sym.accept (this);
			}
			return;
		}

		var sorted_symbols = new ArrayList<Symbol> ();
		foreach (Symbol sym in symbols) {
			int left = 0;
			int right = sorted_symbols.size - 1;
			if (left > right || sym.name < sorted_symbols[left].name) {
				sorted_symbols.insert (0, sym);
			} else if (sym.name > sorted_symbols[right].name) {
				sorted_symbols.add (sym);
			} else {
				while (right - left > 1) {
					int i = (right + left) / 2;
					if (sym.name > sorted_symbols[i].name) {
						left = i;
					} else {
						right = i;
					}
				}
				sorted_symbols.insert (left + 1, sym);
			}
		}
		foreach (Symbol sym in sorted_symbols) {
			sym.accept (this);
		}
	}

	public override void visit_struct (Struct st) {
		if (st.external_package) {
			return;
		}

		if (!check_accessibility (st)) {
			return;
		}
		
		if (st.is_immutable) {
			write_indent ();
			write_string ("[Immutable]");
			write_newline ();
		}

		emit_deprecated_attribute (st);
		emit_experimental_attribute (st);

		write_indent ();

		write_string ("[CCode (");

		if (st.get_cname () != st.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (st.get_cname ()));
		}

		if (!st.has_type_id) {
			write_string ("has_type_id = false, ");
		} else if (!st.is_simple_type () && st.get_type_id () != "G_TYPE_POINTER") {
			write_string ("type_id = \"%s\", ".printf (st.get_type_id ()));
		}

		if (!st.has_copy_function) {
			write_string ("has_copy_function = false, ");
		}

		if (!st.has_destroy_function) {
			write_string ("has_destroy_function = false, ");
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st)));
		write_newline ();

		if (st.is_simple_type ()) {
			write_indent ();
			write_string ("[SimpleType]");
			write_newline ();
		}

		if (st.is_integer_type ()) {
			write_indent ();
			write_string ("[IntegerType (rank = %d)]".printf (st.get_rank ()));
			write_newline ();
		}

		if (st.is_floating_type ()) {
			write_indent ();
			write_string ("[FloatingType (rank = %d)]".printf (st.get_rank ()));
			write_newline ();
		}

		write_attributes (st);

		write_indent ();
		write_accessibility (st);
		write_string ("struct ");
		write_identifier (st.name);

		if (st.base_type != null) {
			write_string (" : ");
			write_type (st.base_type);
		}

		write_begin_block ();

		current_scope = st.scope;

		foreach (Field field in st.get_fields ()) {
			field.accept (this);
		}
		visit_sorted (st.get_constants ());
		visit_sorted (st.get_methods ());
		visit_sorted (st.get_properties ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_interface (Interface iface) {
		if (iface.external_package) {
			return;
		}

		if (!check_accessibility (iface)) {
			return;
		}

		emit_deprecated_attribute (iface);
		emit_experimental_attribute (iface);

		write_indent ();

		write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface)));
		if (iface.get_lower_case_csuffix () != iface.get_default_lower_case_csuffix ())
			write_string (", lower_case_csuffix = \"%s\"".printf (iface.get_lower_case_csuffix ()));
		if (iface.get_type_cname () != iface.get_default_type_cname ())
			write_string (", type_cname = \"%s\"".printf (iface.get_type_cname ()));
		if (iface.get_type_id () != iface.get_default_type_id ())
			write_string (", type_id = \"%s\"".printf (iface.get_type_id ()));

		write_string (")]");
		write_newline ();

		write_attributes (iface);

		write_indent ();
		write_accessibility (iface);
		write_string ("interface ");
		write_identifier (iface.name);

		var type_params = iface.get_type_parameters ();
		if (type_params.size > 0) {
			write_string ("<");
			bool first = true;
			foreach (TypeParameter type_param in type_params) {
				if (first) {
					first = false;
				} else {
					write_string (",");
				}
				write_identifier (type_param.name);
			}
			write_string (">");
		}

		var prerequisites = iface.get_prerequisites ();
		if (prerequisites.size > 0) {
			write_string (" : ");
		
			bool first = true;
			foreach (DataType prerequisite in prerequisites) {
				if (!first) {
					write_string (", ");
				} else {
					first = false;
				}
				write_type (prerequisite);
			}
		}
		write_begin_block ();

		current_scope = iface.scope;

		visit_sorted (iface.get_classes ());
		visit_sorted (iface.get_structs ());
		visit_sorted (iface.get_enums ());
		visit_sorted (iface.get_delegates ());
		visit_sorted (iface.get_fields ());
		visit_sorted (iface.get_constants ());
		visit_sorted (iface.get_methods ());
		visit_sorted (iface.get_properties ());
		visit_sorted (iface.get_signals ());

		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_enum (Enum en) {
		if (en.external_package) {
			return;
		}

		if (!check_accessibility (en)) {
			return;
		}

		emit_deprecated_attribute (en);
		emit_experimental_attribute (en);

		write_indent ();

		write_string ("[CCode (cprefix = \"%s\", ".printf (en.get_cprefix ()));

		if (!en.has_type_id) {
			write_string ("has_type_id = false, ");
		}

		if (en.get_cname () != en.get_default_cname ()) {
			write_string ("cname = \"%s\", ".printf (en.get_cname ()));
		}

		write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en)));

		if (en.is_flags) {
			write_indent ();
			write_string ("[Flags]");
		}

		write_attributes (en);

		write_indent ();
		write_accessibility (en);
		write_string ("enum ");
		write_identifier (en.name);
		write_begin_block ();

		bool first = true;
		foreach (EnumValue ev in en.get_values ()) {
			if (first) {
				first = false;
			} else {
				write_string (",");
				write_newline ();
			}

			if (ev.get_cname () != ev.get_default_cname ()) {
				write_indent ();
				write_string ("[CCode (cname = \"%s\")]".printf (ev.get_cname ()));
			}
			write_indent ();
			write_identifier (ev.name);

			if (type == CodeWriterType.FAST && ev.value != null) {
				write_string(" = ");
				ev.value.accept (this);
			}
		}

		if (!first) {
			if (en.get_methods ().size > 0 || en.get_constants ().size > 0) {
				write_string (";");
			}
			write_newline ();
		}

		current_scope = en.scope;
		foreach (Method m in en.get_methods ()) {
			m.accept (this);
		}
		foreach (Constant c in en.get_constants ()) {
			c.accept (this);
		}
		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_error_domain (ErrorDomain edomain) {
		if (edomain.external_package) {
			return;
		}

		if (!check_accessibility (edomain)) {
			return;
		}

		emit_deprecated_attribute (edomain);
		emit_experimental_attribute (edomain);

		write_indent ();

		write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain.get_cprefix (), get_cheaders(edomain)));

		write_attributes (edomain);

		write_indent ();
		write_accessibility (edomain);
		write_string ("errordomain ");
		write_identifier (edomain.name);
		write_begin_block ();

		bool first = true;
		foreach (ErrorCode ecode in edomain.get_codes ()) {
			if (first) {
				first = false;
			} else {
				write_string (",");
				write_newline ();
			}

			if (ecode.get_cname () != ecode.get_default_cname ()) {
				write_indent ();
				write_string ("[CCode (cname = \"%s\")]".printf (ecode.get_cname ()));
			}
			write_indent ();
			write_identifier (ecode.name);
		}

		if (!first) {
			if (edomain.get_methods ().size > 0) {
				write_string (";");
			}
			write_newline ();
		}

		current_scope = edomain.scope;
		foreach (Method m in edomain.get_methods ()) {
			m.accept (this);
		}
		current_scope = current_scope.parent_scope;

		write_end_block ();
		write_newline ();
	}

	public override void visit_constant (Constant c) {
		if (c.external_package) {
			return;
		}

		if (!check_accessibility (c)) {
			return;
		}

		emit_deprecated_attribute (c);
		emit_experimental_attribute (c);

		bool custom_cname = (c.get_cname () != c.get_default_cname ());
		bool custom_cheaders = (c.parent_symbol is Namespace);
{'fraction_non_alphanumeric': 0.14849718396252717, 'fraction_numerical': 0.002369932526626889, 'mean_word_length': 3.473868030435325, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6781783', 'n_tokens_mistral': 14440, 'n_tokens_neox': 12307, 'n_words': 2677}