remove obsolete ref modifier and callback keyword
[vala-lang.git] / vala / valacodecontext.vala
blob6d1271a7e2d1ac1c7e2c5f66b6167e831e8915c0
1 /* valacodecontext.vala
3 * Copyright (C) 2006-2007 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * The root of the code tree.
28 public class Vala.CodeContext {
29 /**
30 * Specifies the name of the library to be built.
32 * Public header files of a library will be assumed to be installed in
33 * a subdirectory named like the library.
35 public string library { get; set; }
37 /**
38 * Enable automatic memory management.
40 public bool memory_management { get; set; }
42 /**
43 * Enable run-time checks for programming errors.
45 public bool assert { get; set; }
47 /**
48 * Enable additional run-time checks.
50 public bool checking { get; set; }
52 /**
53 * Output C code, don't compile to object code.
55 public bool ccode_only { get; set; }
57 /**
58 * Compile but do not link.
60 public bool compile_only { get; set; }
62 /**
63 * Output filename.
65 public string output { get; set; }
67 /**
68 * Produce debug information.
70 public bool debug { get; set; }
72 /**
73 * Optimization level.
75 public int optlevel { get; set; }
77 /**
78 * Specifies the optional module initialization method.
80 public Method module_init_method { get; set; }
82 List<SourceFile> source_files;
83 private Symbol! root = new Symbol ();
85 List<SourceFileCycle> cycles;
87 private List<string> packages;
89 /**
90 * Returns the root symbol of the code tree.
92 * @return root symbol
94 public Symbol! get_root () {
95 return root;
98 /**
99 * Returns a copy of the list of source files.
101 * @return list of source files
103 public List<weak SourceFile> get_source_files () {
104 return source_files.copy ();
108 * Adds the specified file to the list of source files.
110 * @param file a source file
112 public void add_source_file (SourceFile! file) {
113 source_files.append (file);
117 * Returns a copy of the list of used packages.
119 * @return list of used packages
121 public List<weak string> get_packages () {
122 return packages.copy ();
126 * Returns whether the specified package is being used.
128 * @param pkg a package name
129 * @return true if the specified package is being used
131 public bool has_package (string! pkg) {
132 return packages.find_custom (pkg, strcmp) != null;
136 * Adds the specified package to the list of used packages.
138 * @param pkg a package name
140 public void add_package (string! pkg) {
141 packages.append (pkg);
145 * Visits the complete code tree file by file.
147 * @param visitor the visitor to be called when traversing
149 public void accept (CodeVisitor! visitor) {
150 foreach (SourceFile file in source_files) {
151 file.accept (visitor);
156 * Find and resolve cycles in source file dependencies.
158 public void find_header_cycles () {
159 /* find cycles in dependencies between source files */
160 foreach (SourceFile file in source_files) {
161 /* we're only interested in internal source files */
162 if (file.pkg) {
163 continue;
166 if (file.mark == 0) {
167 visit (file, null);
171 /* find one head for each cycle, it must not have any
172 * hard dependencies on other files in the cycle
174 foreach (SourceFileCycle cycle in cycles) {
175 cycle.head = find_cycle_head ((SourceFile) cycle.files.data);
176 cycle.head.is_cycle_head = true;
179 /* connect the source files in a non-cyclic way
180 * cycle members connect to the head of their cycle
182 foreach (SourceFile file2 in source_files) {
183 /* we're only interested in internal source files */
184 if (file2.pkg) {
185 continue;
188 foreach (SourceFile dep in file2.get_header_internal_dependencies ()) {
189 if (file2.cycle != null && dep.cycle == file2.cycle) {
190 /* in the same cycle */
191 if (!file2.is_cycle_head) {
192 /* include header of cycle head */
193 file2.add_header_internal_include (file2.cycle.head.get_cinclude_filename ());
195 } else {
196 /* we can just include the headers if they are not in a cycle or not in the same cycle as the current file */
197 file2.add_header_internal_include (dep.get_cinclude_filename ());
204 private weak SourceFile find_cycle_head (SourceFile! file) {
205 foreach (SourceFile dep in file.get_header_internal_full_dependencies ()) {
206 if (dep == file) {
207 /* ignore file-internal dependencies */
208 continue;
211 foreach (SourceFile cycle_file in file.cycle.files) {
212 if (dep == cycle_file) {
213 return find_cycle_head (dep);
217 /* no hard dependencies on members of the same cycle found
218 * source file suitable as cycle head
220 return file;
223 private void visit (SourceFile! file, List<SourceFile> chain) {
224 /* no deep copy available yet
225 * var l = chain.copy ();
227 List<weak SourceFile> l = null;
228 foreach (SourceFile chain_file in chain) {
229 l.append (chain_file);
231 l.append (file);
232 /* end workaround */
234 /* mark file as currently being visited */
235 file.mark = 1;
237 foreach (SourceFile dep in file.get_header_internal_dependencies ()) {
238 if (file == dep) {
239 continue;
242 if (dep.mark == 1) {
243 /* found cycle */
245 var cycle = new SourceFileCycle ();
246 cycles.append (cycle);
248 bool cycle_start_found = false;
249 foreach (SourceFile cycle_file in l) {
250 SourceFileCycle ref_cycle_file_cycle = cycle_file.cycle;
251 if (!cycle_start_found) {
252 if (cycle_file == dep) {
253 cycle_start_found = true;
257 if (!cycle_start_found) {
258 continue;
261 if (cycle_file.cycle != null) {
262 /* file already in a cycle */
264 if (cycle_file.cycle == cycle) {
265 /* file is in the same cycle, nothing to do */
266 continue;
269 /* file is in an other cycle, merge the two cycles */
271 /* broken memory management cycles.remove (cycle_file.cycle); */
272 List<weak SourceFileCycle> newlist = null;
273 foreach (SourceFileCycle oldcycle in cycles) {
274 if (oldcycle != cycle_file.cycle) {
275 newlist.append (oldcycle);
278 cycles = null;
279 foreach (SourceFileCycle newcycle in newlist) {
280 cycles.append (newcycle);
282 newlist = null;
283 /* end workaround for broken memory management */
285 foreach (SourceFile inner_cycle_file in cycle_file.cycle.files) {
286 if (inner_cycle_file.cycle != cycle) {
287 /* file in inner cycle not yet added to outer cycle */
288 cycle.files.append (inner_cycle_file);
289 inner_cycle_file.cycle = cycle;
292 } else {
293 cycle.files.append (cycle_file);
294 cycle_file.cycle = cycle;
297 } else if (dep.mark == 0) {
298 /* found not yet visited file */
300 visit (dep, l);
304 /* mark file as successfully visited */
305 file.mark = 2;