Permalink
Browse files

[fix] parser construct and stdlib.core.parser: fix loop behaviour wit…

…h '*', '+' used with non progressing parser

when '*' and '+' construct were used with non progressing rules, the old behaviour was too loop
the new behaviour is to detect such situation and to finish the '*' and '+' construct with proper status

for instance with:
many_a = parser .* -> void
many_ab = parser many_a* "b" -> void

before:
the parser many_a can always be successful by parsing nothing
so the parser many_ab applies repeatedly with success the parser many_a at the start of the input in loop

now:
when no progress is made in a repeating construction ('+','*'), the construction is done
  • Loading branch information...
1 parent 8cbc586 commit 48cdff018ef06e9cd33ef6f9841ad95d7b334a50 @OpaOnWindowsNow OpaOnWindowsNow committed Sep 5, 2011
Showing with 13 additions and 9 deletions.
  1. +13 −9 stdlib/core/parser/parser_private.opa
@@ -102,6 +102,10 @@ Parser_private =
| [{~from ~to} | tl] -> (c >= from && c <= to) || aux(tl)
aux(l)
+ @private
+ no_progress(it1,it2) =
+ Itextrator.pos(it1):int == Itextrator.pos(it2)
+
/**
* [primary_list] repeatedly applies a given parsing function on the input
* for as long as it succeeds. The result of [primary_list] is a list of
@@ -112,7 +116,8 @@ Parser_private =
rec aux(acc, pos) =
match f(pos) : option with
| {some = (newpos, res)} ->
- aux(res +> acc, newpos)
+ if no_progress(pos,newpos) then (pos, List.rev(acc))
+ else aux(res +> acc, newpos)
| _ ->
(pos, List.rev(acc))
res = aux([], init_pos);
@@ -125,16 +130,15 @@ Parser_private =
* As [primary_list] but we do not care about the result.
*/
primary_list_no_res(is_plus, f, init_pos) =
- rec aux(pos, input_needed) =
+ rec aux(pos) =
match f(pos) : option with
| {some = (newpos, _)} ->
- aux(newpos, false)
- | _ ->
- if input_needed then
- none
- else
- some((pos, void))
- aux(init_pos, is_plus)
+ if no_progress(pos,newpos) then pos
+ else aux(newpos)
+ | _ -> pos
+ pos = aux(init_pos)
+ if is_plus && no_progress(init_pos,pos) then none
+ else some((pos,void))
/*
* [parse_literal(it, literal)] checks whether the text contained by

0 comments on commit 48cdff0

Please sign in to comment.