lama_byterun/stdlib/Ostap.expr
Dmitry Boulytchev ff197744f6 More Ostap tests
2020-01-22 22:30:34 +03:00

221 lines
No EOL
4.2 KiB
Text

import List;
import Collection;
import Ref;
import Fun;
import Matcher;
local tab, hct;
public fun initOstap () {
tab := ref (emptyHashTab ());
hct := emptyMemo ()
}
public fun cleanupOstap () {
initOstap ()
}
public fun memo (f) {
local t;
f := lookupMemo (hct, f);
--printf ("Memoizing: %x=%s\n", f, f.string);
case findHashTab (deref (tab), f) of
None -> t := ref (emptyMap ()); tab ::= addHashTab (deref (tab), f, t)
| Some (tt) -> t := tt
esac;
fun (k) {
fun (s) {
-- printf ("s=%s\n", s.string);
case findMap (deref (t), s) of
None ->
t ::= addMap (deref (t), s, [addSet (emptySet (), k), emptySet ()]);
f (fun (r) {
-- printf ("Result: %s\n", r.string);
case findMap (deref (t), s) of
Some ([ks, rs]) ->
if memSet (rs, r)
then skip
else
t ::= addMap (deref (t), s, [ks, addSet (rs, r)]);
iterSet (fun (k) {k (r)}, ks)
fi
esac
}
)
(s)
| Some ([ks, rs]) ->
t ::= addMap (deref (t), s, [addSet (ks, k), rs]);
iterSet (k, rs)
esac
}
}
}
public fun token (x) {
fun (k) {
fun (s) {
k $ matchString (s, x)
}
}
}
public fun eof (k) {
fun (s) {
k (endOf (s))
}
}
public fun empty (k) {
fun (s) {k (Succ ({}, s))}
}
public fun alt (a, b) {
fun (k) {
fun (s) {
a (k) (s);
b (k) (s)
}
}
}
public fun seq (a, b) {
fun (k) {
fun (s) {
a (fun (ar) {
case ar of
Succ (x, s) -> b (x) (k) (s)
| _ -> k (ar)
esac
}) (s)
}
}
}
public infixr | before !! (a, b) {alt (a, b)}
public infixr |> after | (a, b) {seq (a, b)}
public infix @ at * (a, f) {
fun (k) {
fun (s) {
a (fun (x) {k (case x of
Succ (x, s) -> Succ (f (x), s)
| _ -> x
esac)}) (s)
}
}
}
public fun lift (f) {
fun (x) {f}
}
public fun bypass (f) {
fun (x) {f @ lift (x)}
}
public fun opt (a) {empty @ lift (None) | a @ fun (x) {Some (x)}}
public fun rep0 (a) {
memo (empty @ lift({}) | a |> fun (x) {rep0 (a) @ fun (as) {x : as}})
}
public fun rep (a) {
memo (a |> (fun (x) {rep0 (a) @ fun (as) {x : as}}))
}
public fun listBy (item, sep) {
item |> fun (i) {rep0 (sep |> lift (item)) @ fun (is) {i : is}}
}
public fun list0By (item, sep) {
empty @ lift ({}) | listBy (item, sep)
}
public fun list (item) {
listBy (item, token (","))
}
public fun list0 (item) {
list0By (item, token (","))
}
public fun observe (name, f) {
fun (k) {
fun (s) {
printf ("%s at %s\n", name, s.string);
f (k)(s)
}
}
}
fun createResult () {
local errors = ref ({}),
line = ref (0),
col = ref (0),
value = ref ({}),
hasError = ref (false),
hasValue = ref (false);
fun k (x) {
case x of
Succ (val, _) ->
if deref (hasValue)
then failure (sprintf ("Ostap: ambiguous parsing (%s vs. %s)", deref (value).string, val.string))
else
hasValue ::= true;
value ::= val
fi
| Fail (err, l, c) ->
if deref (hasError)
then
local c = compare ([line, col], [l, c]);
if c == 0 then errors ::= err : deref (errors)
elif c < 0 then errors ::= singleton (err); line ::= l; col ::= c
fi
else
hasError ::= true;
errors ::= singleton (err);
line ::= l;
col ::= c
fi
esac
}
fun get () {
if deref (hasValue) then Succ (deref (value))
elif deref (hasError) then Fail (deref (errors), deref (line), deref (col))
else failure ("Ostap::createAcceptor::get: nothing to return")
fi
}
[k, get]
}
fun k (acc) {
acc [0]
}
fun result (acc) {
acc [1] ()
}
public fun parse (p, m) {
local acc = createResult ();
p (acc.k) (m);
acc.result
}
public fun parseString (p, s) {
local acc = createResult ();
p (acc.k) (initMatcher (s));
acc.result
}