libvaladoc: Replace void* with corresponding Vala API
[vala-gnome.git] / libvaladoc / parser / parser.vala
blobacf1d82be155f9c5b4c8164e3ca40ee2bcdb6fee
1 /* parser.vala
3 * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
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 * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
24 public errordomain Valadoc.ParserError {
25 INTERNAL_ERROR,
26 UNEXPECTED_TOKEN
29 public class Valadoc.Parser : ParserCallback {
31 public Parser (Settings settings, Scanner scanner, ErrorReporter reporter) {
32 _settings = settings;
33 _scanner = scanner;
34 _reporter = reporter;
36 TokenType.init_token_types ();
39 private Settings _settings;
40 private Scanner _scanner;
41 private ErrorReporter _reporter;
42 private Rule _root_rule;
44 private string _filename;
45 private int _first_line;
46 private int _first_column;
47 private Token _current_token;
49 private Vala.ArrayList<Rule> rule_stack = new Vala.ArrayList<Rule> ();
50 private Vala.ArrayList<Object?> rule_state_stack = new Vala.ArrayList<Object?> ();
52 public void set_root_rule (Rule root_rule) {
53 _root_rule = root_rule;
56 public void parse (string content, string filename, int first_line, int first_column)
57 throws ParserError
59 _filename = filename;
60 _first_line = first_line;
61 _first_column = first_column;
63 rule_stack.clear ();
64 rule_state_stack.clear ();
66 try {
67 push_rule (_root_rule);
68 _scanner.reset ();
69 _scanner.scan (content);
70 _scanner.end ();
72 if (rule_stack.size != 0) {
73 error (null, "Rule stack is not empty!");
75 } catch (ParserError e) {
76 #if DEBUG
77 log_error (e.message);
78 #endif
79 // Set an in_error boolean, try to recover
80 // And only throw the error at the end of parse ?
81 throw e;
85 public void accept_token (Token token) throws ParserError {
86 #if HARD_DEBUG
87 debug ("Incomming token: %s", token.to_pretty_string ());
88 #endif
90 _current_token = token;
91 int rule_depth = rule_stack.size;
92 Rule.Forward forward = Rule.Forward.NONE;
93 Rule? rule = peek_rule ();
94 if (rule == null) {
95 throw new ParserError.INTERNAL_ERROR ("Rule stack is empty!");
97 while (rule != null) {
98 if (rule.accept_token (token, this, forward)) {
99 break;
102 // Check for invalid recursion
103 if (rule_depth != rule_stack.size && peek_rule () == rule) {
104 error (null, "Parser state error");
105 break;
107 rule = peek_rule ();
109 // Rule stack size have changed
110 // Check for propagation
111 forward = rule_depth > rule_stack.size ? Rule.Forward.CHILD
112 : Rule.Forward.PARENT;
113 rule_depth = rule_stack.size;
117 private Rule? peek_rule (int offset = -1) {
118 assert (offset < 0);
119 if (rule_stack.size + offset < 0) {
120 return null;
122 return rule_stack.get (rule_stack.size + offset);
125 private Rule pop_rule () {
126 int last_index = rule_stack.size - 1;
127 Rule rule = rule_stack.get (last_index);
128 rule_stack.remove_at (last_index);
129 rule_state_stack.remove_at (last_index);
130 return rule;
133 public void push_rule (Rule rule) {
134 rule_stack.add (rule);
135 rule_state_stack.add (null);
137 #if HARD_DEBUG
138 debug ("Pushed at %2d: %s", rule_stack.size - 1, rule.to_string (null));
139 #endif
142 private Object? peek_state (int offset = -1) {
143 assert (offset < 0);
144 if (rule_state_stack.size + offset < 0) {
145 return null;
147 return rule_state_stack.get (rule_state_stack.size + offset);
150 public Object? get_rule_state () {
151 return peek_state ();
154 public void set_rule_state (Object state) {
155 int last_index = rule_stack.size - 1;
156 rule_state_stack.set (last_index, state);
159 public void reduce () {
160 pop_rule ();
162 #if HARD_DEBUG
163 Rule? parent_rule = peek_rule ();
164 if (parent_rule != null) {
165 debug ("Reduced to %2d: %s", rule_stack.size - 1,
166 parent_rule.to_string (peek_state ()));
168 #endif
171 public bool would_parent_accept_token (Token token) {
172 int offset = -2;
173 Rule? parent_rule = peek_rule (offset);
174 Object? state = peek_state (offset);
175 while (parent_rule != null) {
176 #if VERY_HARD_DEBUG
177 debug ("WouldAccept - Offset %d; Index %d: %s", offset,
178 rule_stack.size + offset, parent_rule.to_string (state));
179 #endif
180 if (parent_rule.would_accept_token (token, state)) {
181 #if VERY_HARD_DEBUG
182 debug ("WouldAccept - Yes");
183 #endif
184 return true;
186 if (!parent_rule.would_reduce (token, state)) {
187 #if VERY_HARD_DEBUG
188 debug ("WouldAccept - No");
189 #endif
190 return false;
192 offset--;
193 parent_rule = peek_rule (offset);
194 state = peek_state (offset);
196 #if VERY_HARD_DEBUG
197 debug ("WouldAccept - No");
198 #endif
199 return false;
202 public bool would_parent_reduce_to_rule (Token token, Rule rule) {
203 int offset = -2;
204 Rule? parent_rule = peek_rule (offset);
205 Object? state = peek_state (offset);
206 while (parent_rule != null) {
207 #if VERY_HARD_DEBUG
208 debug ("WouldReduce - Offset %d; Index %d: %s", offset,
209 rule_stack.size + offset, parent_rule.to_string (state));
210 #endif
211 if (!parent_rule.would_reduce (token, state)) {
212 break;
214 offset--;
215 parent_rule = peek_rule (offset);
216 state = peek_state (offset);
218 if ((parent_rule != null && parent_rule.would_accept_token (token, state))
219 || (parent_rule == null && TokenType.EOF.matches (token))) {
220 #if VERY_HARD_DEBUG
221 debug ("WouldReduce - Yes");
222 #endif
223 return true;
225 #if VERY_HARD_DEBUG
226 debug ("WouldReduce - No");
227 #endif
228 return false;
231 public void warning (Token? token, string message) {
232 string error_message;
234 if (token != null) {
235 error_message = message + ": " + token.to_pretty_string ();
236 } else {
237 error_message = message;
240 _reporter.warning (_filename,
241 get_line (token),
242 get_start_column (token),
243 get_end_column (token),
244 _scanner.get_line_content (),
245 error_message);
248 public void error (Token? token, string message) throws ParserError {
249 string error_message;
251 if (token != null) {
252 error_message = message + ": " + token.to_pretty_string ();
253 } else {
254 error_message = message;
257 _reporter.error (_filename,
258 get_line (token),
259 get_start_column (token),
260 get_end_column (token),
261 _scanner.get_line_content (),
262 error_message);
264 throw new ParserError.UNEXPECTED_TOKEN (error_message);
267 private int get_line (Token? token) {
268 if (token == null) {
269 token = _current_token;
271 return token.begin.line + _first_line;
274 private int get_start_column (Token? token) {
275 if (token == null) {
276 token = _current_token;
278 if (token.begin.line == 0) {
279 return token.begin.column + _first_column + 1;
280 } else {
281 return token.begin.column + 1;
285 private int get_end_column (Token? token) {
286 if (token == null) {
287 token = _current_token;
289 if (token.end.line == 0) {
290 return token.end.column + _first_column + 1;
291 } else {
292 return token.end.column + 1;
296 #if DEBUG
297 private void log_error (string message) {
298 stderr.printf ("An error occured while parsing: %s\n", message);
299 stderr.printf ("\nDumping rule stack:\n");
300 for (int i = 0; i < rule_stack.size; i++) {
301 stderr.printf ("\t%2d: %s\n", i, rule_stack[i].to_string (rule_state_stack[i]));
304 #endif