summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@osg.samsung.com>2015-06-23 15:28:46 +0100
committerDaniel Kolesa <d.kolesa@osg.samsung.com>2015-06-23 15:28:46 +0100
commitc26134df7a43292e2dedee26da8aa62415528657 (patch)
treef50961edccbe1ed9fabcdbd6c6b054d2360a148e /src
parentd9db8888ac51175e350853597b3b317e9774a00a (diff)
eolian: new doc token lexer/parser
This should allow us to more easily extend the format if desired and overall makes the doc syntax parsing more readable and simpler.
Diffstat (limited to 'src')
-rw-r--r--src/lib/eolian/eo_lexer.c269
1 files changed, 124 insertions, 145 deletions
diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c
index ac59c6d..24d7080 100644
--- a/src/lib/eolian/eo_lexer.c
+++ b/src/lib/eolian/eo_lexer.c
@@ -252,185 +252,164 @@ cend:
252 if (tok) tok->value.s = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); 252 if (tok) tok->value.s = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
253} 253}
254 254
255void doc_error(Eo_Lexer *ls, const char *msg, Eolian_Documentation *doc, Eina_Strbuf *buf) 255enum Doc_Tokens {
256{ 256 DOC_MANGLED = -2, DOC_UNFINISHED = -1, DOC_TEXT = 0, DOC_SINCE = 1
257 eina_stringshare_del(doc->summary); 257};
258 eina_stringshare_del(doc->description);
259 free(doc);
260 eina_strbuf_free(buf);
261 eo_lexer_lex_error(ls, msg, -1);
262}
263 258
264static void 259static int
265read_doc(Eo_Lexer *ls, Eo_Token *tok, int line, int column) 260doc_lex(Eo_Lexer *ls, Eina_Bool *term, Eina_Bool allow_since)
266{ 261{
267 Eolian_Documentation *doc = calloc(1, sizeof(Eolian_Documentation)); 262 Eina_Bool contdoc = EINA_FALSE;
268 doc->base.file = ls->filename;
269 doc->base.line = line;
270 doc->base.column = column;
271
272 eina_strbuf_reset(ls->buff); 263 eina_strbuf_reset(ls->buff);
273 264 for (;; contdoc = EINA_TRUE) switch (ls->current)
274 skip_ws(ls);
275 while (is_newline(ls->current))
276 next_line_ws(ls);
277
278 for (;;)
279 { 265 {
280 if (!ls->current) 266 /* error case */
267 case '\0':
268 return DOC_UNFINISHED;
269 /* newline case: if two or more newlines are present, new paragraph
270 * if only one newline is present, append space to the text buffer
271 * when starting new paragraph, reset doc continutation
272 */
273 case '\n':
274 case '\r':
275 next_line(ls);
276 skip_ws(ls);
277 if (!is_newline(ls->current))
281 { 278 {
282 doc_error(ls, "unfinished documentation", doc, NULL); 279 eina_strbuf_append_char(ls->buff, ' ');
283 return; /* unreachable, for static analysis */ 280 continue;
284 } 281 }
285 if (is_newline(ls->current)) 282 while (is_newline(ls->current))
283 next_line_ws(ls);
284 eina_strbuf_trim(ls->buff);
285 return DOC_TEXT;
286 /* escape case: for any \X, output \X
287 * except for \\]], then output just ]]
288 */
289 case '\\':
290 next_char(ls);
291 if (ls->current == ']')
286 { 292 {
287 next_line_ws(ls); 293 next_char(ls);
288 if (is_newline(ls->current)) 294 if (ls->current == ']')
289 { 295 {
290 while (is_newline(ls->current)) 296 next_char(ls);
291 next_line_ws(ls); 297 eina_strbuf_append(ls->buff, "]]");
292 break;
293 } 298 }
294 else 299 else
295 eina_strbuf_append_char(ls->buff, ' '); 300 eina_strbuf_append(ls->buff, "\\]");
296 } 301 }
297 else 302 else
303 eina_strbuf_append_char(ls->buff, '\\');
304 continue;
305 /* terminating case */
306 case ']':
307 next_char(ls);
308 if (ls->current == ']')
298 { 309 {
299 if (ls->current == ']') 310 /* terminate doc */
300 {
301 next_char(ls);
302 if (ls->current != ']')
303 eina_strbuf_append_char(ls->buff, ']');
304 else
305 {
306 next_char(ls);
307 eina_strbuf_trim(ls->buff);
308 doc->summary = eina_stringshare_add(
309 eina_strbuf_string_get(ls->buff));
310 tok->value.doc = doc;
311 return;
312 }
313 }
314 eina_strbuf_append_char(ls->buff, ls->current);
315 next_char(ls); 311 next_char(ls);
312 *term = EINA_TRUE;
313 eina_strbuf_trim(ls->buff);
314 return DOC_TEXT;
316 } 315 }
317 } 316 eina_strbuf_append_char(ls->buff, ']');
318 317 continue;
319 eina_strbuf_trim(ls->buff); 318 /* @since case - only when starting a new paragraph */
320 doc->summary = eina_stringshare_add(eina_strbuf_string_get(ls->buff)); 319 case '@':
321 320 eina_strbuf_append_char(ls->buff, '@');
322 Eina_Strbuf *rbuf = eina_strbuf_new(); 321 next_char(ls);
323 Eina_Bool had_nl = EINA_TRUE; 322 while (ls->current && isalpha(ls->current))
324
325 for (;;)
326 {
327 if (!ls->current)
328 { 323 {
329 doc_error(ls, "unfinished documentation", doc, rbuf); 324 eina_strbuf_append_char(ls->buff, ls->current);
330 return; /* unreachable, for static analysis */ 325 next_char(ls);
331 } 326 }
332 327 if (contdoc)
333 eina_strbuf_reset(ls->buff); 328 continue;
334 329 if (!strcmp(eina_strbuf_string_get(ls->buff), "@since"))
335 if (had_nl && ls->current == '@')
336 { 330 {
337#define LEX_SINCE(c, failure) \ 331 /* since-token */
338 next_char(ls); \ 332 if (!allow_since)
339 if (ls->current != c) \ 333 return DOC_MANGLED;
340 { \ 334 *term = EINA_TRUE;
341 eina_strbuf_append(ls->buff, failure); \ 335 eina_strbuf_reset(ls->buff);
342 goto normal; \
343 }
344
345 LEX_SINCE('s', "@");
346 LEX_SINCE('i', "@s");
347 LEX_SINCE('n', "@si");
348 LEX_SINCE('c', "@sin");
349 LEX_SINCE('e', "@sinc");
350 LEX_SINCE(' ', "@since");
351
352#undef LEX_SINCE
353
354 skip_ws(ls); 336 skip_ws(ls);
355 337 while (ls->current && (ls->current == '.' ||
356 /* gotta have a value */ 338 ls->current == '_' ||
357 if (!ls->current || is_newline(ls->current) || ls->current == ']') 339 isalnum(ls->current)))
358 goto docerr;
359
360 /* append the since string */
361 while (ls->current && ls->current != ']' && !is_newline(ls->current))
362 { 340 {
363 eina_strbuf_append_char(ls->buff, ls->current); 341 eina_strbuf_append_char(ls->buff, ls->current);
364 next_char(ls); 342 next_char(ls);
365 } 343 }
344 if (!eina_strbuf_length_get(ls->buff))
345 return DOC_UNFINISHED;
346 skip_ws(ls);
347 while (is_newline(ls->current))
348 next_line_ws(ls);
349 if (ls->current == ']')
350 next_char(ls);
351 if (ls->current != ']')
352 return DOC_MANGLED;
353 next_char(ls);
354 eina_strbuf_trim(ls->buff);
355 return DOC_SINCE;
356 }
357 /* default case - append character */
358 default:
359 eina_strbuf_append_char(ls->buff, ls->current);
360 next_char(ls);
361 continue;
362 }
363}
366 364
367 /* trigger "unfinished documentation" if things end early */ 365void doc_error(Eo_Lexer *ls, const char *msg, Eolian_Documentation *doc, Eina_Strbuf *buf)
368 if (!ls->current) 366{
369 continue; 367 eina_stringshare_del(doc->summary);
370 368 eina_stringshare_del(doc->description);
371 /* strip final whitespace */ 369 free(doc);
372 while (isspace(ls->current)) 370 eina_strbuf_free(buf);
373 { 371 eo_lexer_lex_error(ls, msg, -1);
374 if (is_newline(ls->current)) 372}
375 next_line(ls);
376 else
377 next_char(ls);
378 }
379 373
380 if (ls->current != ']') goto docerr; 374static void
381 next_char(ls); 375read_doc(Eo_Lexer *ls, Eo_Token *tok, int line, int column)
382 if (ls->current != ']') goto docerr; 376{
383 next_char(ls); 377 Eolian_Documentation *doc = calloc(1, sizeof(Eolian_Documentation));
378 doc->base.file = ls->filename;
379 doc->base.line = line;
380 doc->base.column = column;
384 381
385 eina_strbuf_trim(ls->buff); 382 Eina_Strbuf *rbuf = eina_strbuf_new();
386 doc->since = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
387 383
388 goto done; 384 Eina_Bool term = EINA_FALSE;
389docerr: 385 while (!term)
386 {
387 int read = doc_lex(ls, &term, !!doc->summary);
388 switch (read)
389 {
390 case DOC_MANGLED:
390 doc_error(ls, "mangled documentation", doc, rbuf); 391 doc_error(ls, "mangled documentation", doc, rbuf);
391 return; 392 return;
392 } 393 case DOC_UNFINISHED:
393 394 doc_error(ls, "unfinished documentation", doc, rbuf);
394normal: 395 return;
395 had_nl = EINA_FALSE; 396 case DOC_TEXT:
396 while (ls->current && !is_newline(ls->current)) 397 if (!doc->summary)
397 { 398 doc->summary = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
398 if (ls->current == ']') 399 else
399 { 400 {
400 next_char(ls); 401 if (eina_strbuf_length_get(rbuf))
401 if (ls->current != ']') 402 eina_strbuf_append(rbuf, "\n\n");
402 eina_strbuf_append_char(ls->buff, ']'); 403 eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff));
403 else
404 {
405 next_char(ls);
406 eina_strbuf_trim(ls->buff);
407 eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff));
408 goto done;
409 }
410 } 404 }
411 eina_strbuf_append_char(ls->buff, ls->current); 405 break;
412 next_char(ls); 406 case DOC_SINCE:
413 } 407 doc->since = eina_stringshare_add(eina_strbuf_string_get(ls->buff));
414 eina_strbuf_trim(ls->buff); 408 break;
415 eina_strbuf_append(rbuf, eina_strbuf_string_get(ls->buff));
416
417 if (is_newline(ls->current))
418 {
419 next_line_ws(ls);
420 /* new paragraph */
421 if (is_newline(ls->current))
422 eina_strbuf_append(rbuf, "\n\n");
423 else
424 eina_strbuf_append_char(rbuf, ' ');
425 while (is_newline(ls->current))
426 next_line_ws(ls);
427 had_nl = EINA_TRUE;
428 } 409 }
429 } 410 }
430 411
431done: 412 if (eina_strbuf_length_get(rbuf))
432 eina_strbuf_trim(rbuf);
433 if (eina_strbuf_string_get(rbuf)[0])
434 doc->description = eina_stringshare_add(eina_strbuf_string_get(rbuf)); 413 doc->description = eina_stringshare_add(eina_strbuf_string_get(rbuf));
435 eina_strbuf_free(rbuf); 414 eina_strbuf_free(rbuf);
436 tok->value.doc = doc; 415 tok->value.doc = doc;