#include "share/atspre_staload.hats"
// following: http://languagengine.co/blog/differentiating-regular-expressions/
staload _ = "prelude/DATS/list_vt.dats"
datatype Regex
= RElit of char // individual characters are regexes
| REcat of (Regex, Regex) // if E and F are regexes, so is EF
| REalt of (Regex, Regex) // if E and F are regexes, so is E|F
| REopt of Regex // if E is a regex, so is E?
| RErep of Regex // if E is a regex, so is E+
datatype LocalRegexContext
= InSeqL of Regex // a Seq with the left arg removed
| InSeqR of Regex // a Seq with the right arg removed
| InAltL of Regex // an Alt with the left arg removed
| InAltR of Regex // an Alt with the right arg removed
| InOpt // an Opt with its only arg removed
| InRep // a Rep with its only arg removed
typedef RegexContext = List (LocalRegexContext)
extern
fun
plug (Regex, LocalRegexContext): Regex
implement
plug (e, ctx) =
case+ ctx of
| InSeqL f => REcat (e, f) // e in _f is ef
| InSeqR f => REcat (f, e) // e in f_ is fe
| InAltL f => REalt (e, f) // e in _|f is e|f
| InAltR f => REalt (f, e) // e in f|_ is f|e
| InOpt () => REopt e // e in _? is e?
| InRep () => RErep e // e in _+ is e+
extern
fun
plugContext (Regex, RegexContext): Regex
implement
plugContext (e, ctx) = let
implement
list_foldleft$fopr<Regex><LocalRegexContext> (acc, ctx) = plug (acc, ctx)
val res = list_foldleft<Regex><LocalRegexContext> (ctx, e)
in
res
end
datatype Direction = Starting | Finishing
typedef RegexState = @(Direction, Regex, RegexContext)
extern
fun
next (RegexState): List_vt RegexState
implement
next (rst) =
case+ rst.0 of
| Starting () => let
in
// this group corresponds to the edges out of starting states
case+ (rst.1, rst.2) of
| (RElit x, c) => $list_vt{RegexState} ((Finishing, RElit x, c) : RegexState)
| (REcat (e, f), c) => let prval () = lemma_list_param c in $list_vt{RegexState} ((Starting, e, list_cons (InSeqL f, c))) end
| (REalt (e, f), c) => let prval () = lemma_list_param c in $list_vt{RegexState} ((Starting, e, list_cons (InAltL f, c)), (Starting, f, list_cons (InAltR e, c))) end
| (REopt e, c) => let prval () = lemma_list_param c in $list_vt{RegexState} ((Starting, e, list_cons (InOpt, c)), (Finishing, REopt e, c)) end
| (RErep e, c) => let prval () = lemma_list_param c in $list_vt{RegexState} ((Starting, e, list_cons (InRep, c))) end
end
| Finishing () => (
// this group corresponds to the edges out of finishing states
case+ (rst.1, rst.2) of
| (e, list_cons (InSeqL f, c)) => $list_vt{RegexState} ((Starting, f, list_cons (InSeqR e, c)))
| (f, list_cons (InSeqR e, c)) => $list_vt{RegexState} ((Finishing, REcat (e, f), c))
| (e, list_cons (InAltL f, c)) => $list_vt{RegexState} ((Finishing, REalt (e, f), c))
| (f, list_cons (InAltR e, c)) => $list_vt{RegexState} ((Finishing, REalt (e, f), c))
| (e, list_cons (InOpt (), c)) => $list_vt{RegexState} ((Finishing, REopt e, c))
| (e, list_cons (InRep (), c)) => $list_vt{RegexState} ((Finishing, RErep e, c), (Starting, e, list_cons (InRep, c)))
| (_, _) => list_vt_nil ()
)
extern
fun
emit (RegexState): List_vt @(char,RegexState)
implement
emit (s) = let
val s' = next (s)
typedef T = @(char,RegexState)
vtypedef VT = List_vt T
implement
list_vt_map$fopr<RegexState><VT> (s') =
case+ s.0 of
| Finishing () => (
case+ s.1 of
| RElit x => $list_vt{T} (@(x, s') : T)
| _ => emit s'
)
| _ => emit s'
// end of [list_vt_map$fopr]
val res = list_vt_map<RegexState><VT> (s')
val () = list_vt_free (s')
val res = list_vt_concat<T> (res)
in
res
end
extern
fun
finishesTrivially (RegexState): bool
implement
finishesTrivially (st) =
case+ st.0 of
| Starting () => let
val c = st.2
prval () = lemma_list_param (c)
in
case+ st.1 of
| RElit _ => false
| REcat (e, f) => finishesTrivially @(Starting (), e, list_cons (InSeqL f, c))
| REalt (e, f) => finishesTrivially @(Starting (), e, list_cons (InAltL f, c))
| REopt e => finishesTrivially @(Finishing (), REopt e, c)
| RErep e => finishesTrivially @(Starting (), e, list_cons (InRep, c))
end
| Finishing () => let
val c = st.2
prval () = lemma_list_param (c)
in
case+ c of
| list_nil () => true
| list_cons (InSeqL f, c) => finishesTrivially @(Starting (), f, list_cons (InSeqR st.1, c))
| list_cons (InSeqR e, c) => finishesTrivially @(Finishing (), REcat (e, st.1), c)
| list_cons (InAltL f, c) => finishesTrivially @(Finishing (), REcat (st.1, f), c)
| list_cons (InAltR e, c) => finishesTrivially @(Finishing (), REcat (e, st.1), c)
| list_cons (InOpt (), c) => finishesTrivially @(Finishing (), REopt st.1, c)
| list_cons (InRep (), c) => finishesTrivially @(Finishing (), RErep st.1, c)
end
extern
fun
consume (char, RegexState): List_vt RegexState
implement
consume (c, s) = let
val s' = emit (s)
typedef T = @(char,RegexState)
implement
list_vt_filter$pred<T> (x) = (x.0 = c)
val res = list_vt_filter<T> (s')
implement
list_vt_map$fopr<T><RegexState> (x) = x.1
val res0 = list_vt_map<T><RegexState> (res)
val () = list_vt_free (res)
in
res0
end
extern
fun
recognize (string, Regex): bool
implement
recognize (cs, e) = let
fun
go {n:nat} (s: string(n), rs: List_vt RegexState): bool =
if string_is_empty (s) then let
implement
list_vt_foreach$cont<RegexState><bool> (x, env) = ~env
implement
list_vt_foreach$fwork<RegexState><bool> (x, env) = env := finishesTrivially (x)
var ans = (g0ofg1)false
val () = list_vt_foreach_env<RegexState><bool> (rs, ans)
val () = list_vt_free (rs)
in
ans
end else let
val c = string_head (s)
val s = string_tail (s)
implement
list_vt_map$fopr<RegexState><List_vt RegexState> (s) = consume (c, s)
val res = list_vt_map<RegexState><List_vt RegexState> (rs)
val () = list_vt_free (rs)
val res = list_vt_concat<RegexState> (res)
in
go (s, res)
end
// end of [go]
val cs = (g1ofg0)cs
val st = $list_vt{RegexState} (@(Starting (), e, list_nil ()))
in
go (cs, st)
end // end of [recognize]
implement main0 () = let
val () = println!("hello world!")
// a(b|c+)d
val re0 = REcat (REcat (RElit 'a', REalt (RElit 'b', RErep (RElit 'c'))), RElit 'd')
val-true = recognize ("abd", re0)
val-true = recognize ("acd", re0)
val-true = recognize ("accd", re0)
val-true = recognize ("acccd", re0)
val-false = recognize ("abbd", re0)
val-false = recognize ("efg", re0)
val () = println!("successfully ran all tests")
in
end
PATSCC=$(PATSHOME)/bin/patscc -DATS_MEMALLOC_LIBC
PATSOPT=$(PATSHOME)/bin/patsopt
PATSOLVE=$(PATSHOME)/bin/patsolve_smt
RMF=rm -f
all: main; ./a.out
main: main.dats; $(PATSCC) main.dats