[Ur] Combinator Parsing in Ur: Anonymous function remains at code generation
Adam Chlipala
adamc at csail.mit.edu
Mon Jul 21 08:17:44 EDT 2014
On 07/17/2014 10:19 PM, orchidaceae phalaenopsis wrote:
> Hi! We're trying to implement Parsec in Ur/Web (following
> http://research.microsoft.com/en-us/um/people/daan/download/papers/parsec-paper.pdf
> ). When trying to use our implementation we got "Anonymous function
> remains at code generation".
>
> [...]
> Here's a test case:
> https://gist.github.com/yuuko273/1352059b69e71d7015dd .
I've pushed an Ur/Web change to the public repository, fixing a
program-analysis bug that stood in the way of your example working.
However, there were two other issues to address, and I've attached my
refactoring of your code, which works fine.
First, you were wrapping parsers inside a single-constructor datatype.
The compiler's program analysis isn't generally smart enough to
understand functions hidden inside datatypes, and program analysis is
needed to remove all uses of first-class functions in server-side code.
I changed the parser type to be a synonym instead, and I also made it an
abstract type in a module, to get type-class resolution to work properly.
> * When attempting to run a parser on the empty string:
>
> Error triggers unlimited retry: Couldn't allocate new heap chunk
> contiguously; increasing size to 1024
> Error triggers unlimited retry: Couldn't allocate new heap chunk
> contiguously; increasing size to 131072
> Error triggers unlimited retry: Couldn't allocate new heap chunk
> contiguously; increasing size to 262144
The issue here was just an infinite loop in your parsing code! Function
[upTo] would diverge on negative [i], which appears when the input
string is empty.
-------------- next part --------------
structure Parse : sig
con parser :: Type -> Type
val runParser : a ::: Type -> parser a -> string -> option a
val monad_parser : monad parser
val satisfy : (char -> bool) -> parser char
val char : char -> parser char
end = struct
datatype reply a = Success of a * list char
| Failure
datatype consumed a = Consumed of reply a
| Empty of reply a
type parser a = list char -> consumed a
fun stringToList (s : string) : list char =
let
fun upTo acc i =
if i < 0 then acc
else if i = 0 then 0 :: acc
else upTo (i :: acc) (i - 1)
in
List.mp (String.sub s) (upTo [] (String.length s - 1))
end
fun runParser [a] (p : parser a) (s : string) : option a =
let
fun reply [a] (r : reply a) : option a =
case r of
Success (a, _) => Some a
| Failure => None
in
case p (stringToList s) of
Consumed r => reply r
| Empty r => reply r
end
fun return' [a] (x : a) : parser a = fn input => Empty (Success (x, input))
fun bind' [a] [b] (p : parser a) (f : a -> parser b) : parser b =
fn input => case p input of
Empty (Success (x, xs)) => f x xs
| Empty Failure => Empty Failure
| Consumed (Success (x, xs)) => f x xs
| Consumed Failure => Consumed Failure
val monad_parser = mkMonad {Bind = @@bind', Return = @@return'}
fun satisfy (test : char -> bool) : parser char =
fn input => case input of
[] => Empty Failure
| x :: xs => if test x then
Consumed (Success (x, xs))
else
Empty Failure
fun char (c : char) : parser char = satisfy (eq c)
end
open Parse
val testcase : parser unit =
_ <- char #"x";
_ <- char #"y";
return ()
fun main () : transaction page =
case (runParser testcase "", runParser testcase "xy") of
(None, Some ()) => return <xml>Tests passed.</xml>
| _ => return <xml>Tests failed.</xml>
More information about the Ur
mailing list