Release 0.7.8
[vala-lang.git] / vala / valasourcefile.vala
blob6650512e2a68a428c025fec90a8258302dc66869
1 /* valasourcefile.vala
3 * Copyright (C) 2006-2009 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.1 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 * Represents a Vala source or VAPI package file.
28 public class Vala.SourceFile {
29 /**
30 * The name of this source file.
32 public string filename { get; set; }
35 /**
36 * Specifies whether this file is a VAPI package file.
38 public bool external_package { get; set; }
40 /**
41 * The context this source file belongs to.
43 public weak CodeContext context { get; set; }
45 public string? content {
46 get { return this._content; }
47 set {
48 this._content = value;
49 this.source_array = null;
53 private ArrayList<Comment> comments = new ArrayList<Comment> ();
55 public List<UsingDirective> current_using_directives { get; set; default = new ArrayList<UsingDirective> (); }
57 private List<CodeNode> nodes = new ArrayList<CodeNode> ();
59 private string csource_filename = null;
60 private string cinclude_filename = null;
62 private ArrayList<string> source_array = null;
64 private MappedFile mapped_file = null;
66 private string? _content = null;
68 /**
69 * Creates a new source file.
71 * @param filename source file name
72 * @param pkg true if this is a VAPI package file
73 * @return newly created source file
75 public SourceFile (CodeContext context, string filename, bool pkg = false, string? content = null) {
76 this.filename = filename;
77 this.external_package = pkg;
78 this.context = context;
79 this.content = content;
82 /**
83 * Adds a header comment to this source file.
85 public void add_comment (Comment comment) {
86 comments.add (comment);
89 /**
90 * Returns a copy of the list of header comments.
92 * @return list of comments
94 public List<Comment> get_comments () {
95 return new ReadOnlyList<Comment> (comments);
98 /**
99 * Adds a new using directive with the specified namespace.
101 * @param ns reference to namespace
103 public void add_using_directive (UsingDirective ns) {
104 // do not modify current_using_directives, it should be considered immutable
105 // for correct symbol resolving
106 var old_using_directives = current_using_directives;
107 current_using_directives = new ArrayList<UsingDirective> ();
108 foreach (var using_directive in old_using_directives) {
109 current_using_directives.add (using_directive);
111 current_using_directives.add (ns);
115 * Adds the specified code node to this source file.
117 * @param node a code node
119 public void add_node (CodeNode node) {
120 nodes.add (node);
123 public void remove_node (CodeNode node) {
124 nodes.remove (node);
128 * Returns a copy of the list of code nodes.
130 * @return code node list
132 public List<CodeNode> get_nodes () {
133 return new ReadOnlyList<CodeNode> (nodes);
136 public void accept (CodeVisitor visitor) {
137 visitor.visit_source_file (this);
140 public void accept_children (CodeVisitor visitor) {
141 foreach (CodeNode node in nodes) {
142 node.accept (visitor);
146 private string get_subdir () {
147 if (context.basedir == null) {
148 return "";
151 // filename and basedir are already canonicalized
152 if (filename.has_prefix (context.basedir + "/")) {
153 var basename = Path.get_basename (filename);
154 var subdir = filename.substring (context.basedir.len (), filename.len () - context.basedir.len () - basename.len ());
155 while (subdir[0] == '/') {
156 subdir = subdir.offset (1);
158 return subdir;
160 return "";
163 private string get_destination_directory () {
164 if (context.directory == null) {
165 return get_subdir ();
167 return "%s/%s".printf (context.directory, get_subdir ());
170 private string get_basename () {
171 long dot = filename.pointer_to_offset (filename.rchr (-1, '.'));
172 return Path.get_basename (filename.substring (0, dot));
175 public string get_relative_filename () {
176 return get_subdir () + Path.get_basename (filename);
180 * Returns the filename to use when generating C source files.
182 * @return generated C source filename
184 public string get_csource_filename () {
185 if (csource_filename == null) {
186 if (context.ccode_only || context.save_csources) {
187 csource_filename = "%s%s.c".printf (get_destination_directory (), get_basename ());
188 } else {
189 // temporary file
190 csource_filename = "%s%s.vala.c".printf (get_destination_directory (), get_basename ());
193 return csource_filename;
197 * Returns the filename to use when including the generated C header
198 * file.
200 * @return C header filename to include
202 public string get_cinclude_filename () {
203 if (cinclude_filename == null) {
204 if (context.header_filename != null) {
205 cinclude_filename = Path.get_basename (context.header_filename);
206 if (context.includedir != null) {
207 cinclude_filename = "%s/%s".printf (context.includedir, cinclude_filename);
209 } else {
210 cinclude_filename = "%s%s.h".printf (get_subdir (), get_basename ());
213 return cinclude_filename;
217 * Returns the requested line from this file, loading it if needed.
219 * @param lineno 1-based line number
220 * @return the specified source line
222 public string? get_source_line (int lineno) {
223 if (source_array == null) {
224 if (content != null) {
225 read_source_lines (content);
226 } else {
227 read_source_file ();
230 if (lineno < 1 || lineno > source_array.size) {
231 return null;
233 return source_array.get (lineno - 1);
237 * Parses the input file into ::source_array.
239 private void read_source_file () {
240 string cont;
241 try {
242 FileUtils.get_contents (filename, out cont);
243 } catch (FileError fe) {
244 return;
246 read_source_lines (cont);
249 private void read_source_lines (string cont)
251 source_array = new ArrayList<string> ();
252 string[] lines = cont.split ("\n", 0);
253 int idx;
254 for (idx = 0; lines[idx] != null; ++idx) {
255 source_array.add (lines[idx]);
259 public char* get_mapped_contents () {
260 if (content != null) {
261 return (char*) content;
264 if (mapped_file == null) {
265 try {
266 mapped_file = new MappedFile (filename, false);
267 } catch (FileError e) {
268 Report.error (null, "Unable to map file `%s': %s".printf (filename, e.message));
269 return null;
273 return mapped_file.get_contents ();
276 public size_t get_mapped_length () {
277 if (content != null) {
278 return content.length;
281 return mapped_file.get_length ();
284 public bool check (SemanticAnalyzer analyzer) {
285 foreach (CodeNode node in nodes) {
286 node.check (analyzer);
288 return true;