//[re2.flx]
include "stl/stl_map";
//$ Binding of Google RE2 regexp library.
open class Re2 {
requires package "re2";
// This is an almost full binding of Google's re2 package.
// We do not support conversions of digits strings to integers
//
// TODO: we need to check the lvalue handling here
// The RE2, Options classes aren't copyable, so we may have
// to use pointers
//
// TODO: named group extractor
// hackery because ::re2::RE2 isn't copyable, so we have to use a pointer
// but we need the shape of RE2 to create on the heap
private body RE2_serial = """
static ::std::string RE2_encoder(void *p) {
return (*(::std::shared_ptr< ::re2::RE2>*)p)->pattern();
}
static size_t RE2_decoder (void *p, char *s, size_t i) {
char tmp[sizeof(::std::string)];
i = ::flx::gc::generic::string_decoder (&tmp,s,i);
new(p) ::std::shared_ptr< ::re2::RE2> (new ::re2::RE2 (*(::std::string*)(&tmp)));
::destroy((::std::string*)&tmp);
return i;
}
""";
/*
private type RE2_ = "::re2::RE2"
;
*/
type RE2 = "::std::shared_ptr< ::re2::RE2>"
requires Cxx11_headers::memory,
RE2_serial, encoder "RE2_encoder", decoder "RE2_decoder"
;
gen _ctor_RE2 : string -> RE2 = "::std::shared_ptr< ::re2::RE2>(new RE2($1))";
type StringPiece = "::re2::StringPiece";
ctor StringPiece: &string = "::re2::StringPiece(*$1)"; // Argument must be reference to variable!
ctor StringPiece: string = "::re2::StringPiece($1)"; // DANGEROUS DEPRECATE
ctor StringPiece: unit = "::re2::StringPiece()";
ctor StringPiece: StringPiece = "::re2::StringPiece($1)"; // copy constructor
ctor StringPiece: +char * !ints = "::re2::StringPiece($1,$2)"; // array and length
ctor StringPiece (x:varray[char]) => StringPiece(x.stl_begin,x.len);
ctor string: StringPiece = "$1.as_string()";
fun len: StringPiece -> size = "(size_t)$1.length()";
fun data: StringPiece -> +char = "(char*)$1.data()"; // cast away const
instance Container[StringPiece,char] {
fun len: StringPiece -> size = "$1.size()";
}
instance Eq[StringPiece] {
fun == : StringPiece * StringPiece -> bool = "$1==$2";
}
instance Tord[StringPiece] {
fun < : StringPiece * StringPiece -> bool = "$1<$2";
}
instance Str[StringPiece] {
fun str: StringPiece -> string ="$1.as_string()";
}
fun subscript (x:StringPiece, s:slice[int]):StringPiece =>
match s with
| #Slice_all => x
| Slice_from (start) =>
// unsafe, FIXME
StringPiece (x.data + start.size, x.len.int - start)
| Slice_to_incl (xend) =>
// unsafe, FIXME
StringPiece (x.data, xend + 1)
| Slice_to_excl (xend) =>
// unsafe, FIXME
StringPiece (x.data, xend)
| Slice_range_incl (start, xend) =>
// unsafe, FIXME
StringPiece (x.data + start.size, xend - start+1)
| Slice_range_excl (start, xend) =>
// unsafe, FIXME
StringPiece (x.data + start, xend - start)
| Slice_one (index) =>
// unsafe, FIXME
StringPiece (x.data + index, 1)
endmatch
;
type Arg = "::re2::Arg";
type Encoding = "::re2::RE2::Encoding";
const EncodingUTF8: Encoding = "::re2::RE2::EncodingUTF8";
const EncodingLatin1: Encoding = "::re2::RE2::EncodingLatin1";
type RE2Options = "::re2::RE2::Options";
proc Copy: RE2Options * RE2Options = "$1.Copy($2);";
fun encoding: RE2Options -> Encoding = "$1.encoding()";
proc set_encoding: RE2Options * Encoding = "$1.set_encoding($2);";
fun posix_syntax: RE2Options -> bool = "$1.posix_syntax()";
proc set_posix_syntax: RE2Options * bool = "$1.set_posix_syntax($2);";
fun longest_match: RE2Options -> bool = "$1.longest_match()";
proc set_longest_match: RE2Options * bool = "$1.set_longest_match($2);";
fun log_errors: RE2Options -> bool = "$1.log_errors()";
proc set_log_errors: RE2Options * bool = "$1.set_log_errors($2);";
fun max_mem: RE2Options -> int = "$1.max_mem()";
proc set_max_mem: RE2Options * int = "$1.set_max_mem($2);";
fun literal: RE2Options -> bool = "$1.literal()";
proc set_literal: RE2Options * bool = "$1.set_literal($2);";
fun never_nl: RE2Options -> bool = "$1.never_nl()";
proc set_never_nl: RE2Options * bool = "$1.set_never_nl($2);";
fun case_sensitive: RE2Options -> bool = "$1.case_sensitive()";
proc set_case_sensitive: RE2Options * bool = "$1.set_case_sensitive($2);";
fun perl_classes: RE2Options -> bool = "$1.perl_classes()";
proc set_perl_classes: RE2Options * bool = "$1.set_perl_classes($2);";
fun word_boundary: RE2Options -> bool = "$1.word_boundary()";
proc set_word_boundary: RE2Options * bool = "$1.set_word_boundary($2);";
fun one_line: RE2Options -> bool = "$1.one_line()";
proc set_one_line: RE2Options * bool = "$1.set_one_line($2);";
fun ParseFlags: RE2Options -> int = "$1.ParseFlags()";
type ErrorCode = "::re2::RE2::ErrorCode";
const NoError : ErrorCode = "::re2::RE2::NoError";
const ErrorInternal: ErrorCode = "::re2::RE2::ErrorInternal";
const ErrorBadEscape : ErrorCode = "::re2::RE2::ErrorBadEscape";
const ErrorBadCharClass : ErrorCode = "::re2::RE2::ErrorBadCharClass";
const ErrorBadCharRange : ErrorCode = "::re2::RE2::ErrorBadCharRange";
const ErrorMissingBracket : ErrorCode = "::re2::RE2::ErrorMissingBracket";
const ErrorMissingParen : ErrorCode = "::re2::RE2::ErrorMissingParen";
const ErrorTrailingBackslash : ErrorCode = "::re2::RE2::ErrorTrailingBackslash";
const ErrorRepeatArgument : ErrorCode = "::re2::RE2::ErrorRepeatArgument";
const ErrorRepeatSize : ErrorCode = "::re2::RE2::ErrorRepeatSize";
const ErrorRepeatOp: ErrorCode = "::re2::RE2::ErrorRepeatOp";
const ErrorBadPerlOp: ErrorCode = "::re2::RE2::ErrprBadPerlOp";
const ErrorBadUTF8: ErrorCode = "::re2::RE2::ErrorBadUTF8";
const ErrorBadNamedCapture: ErrorCode = "::re2::RE2::ErrorBadNamedCapture";
const ErrorPatternTooLarge: ErrorCode = "::re2::RE2::ErrorPatternTooLarge";
type Anchor = "::re2::RE2::Anchor";
const UNANCHORED: Anchor = "::re2::RE2::UNANCHORED";
const ANCHOR_START: Anchor = "::re2::RE2::ANCHOR_START";
const ANCHOR_BOTH: Anchor = "::re2::RE2::ANCHOR_BOTH";
fun pattern: RE2 -> string = "$1->pattern()";
instance Str[RE2] {
fun str (r:RE2) => r.pattern;
}
fun error: RE2 -> string = "$1->error()";
fun error_code: RE2 -> ErrorCode = "$1->error_code()";
fun error_arg: RE2 -> string = "$1->error_arg()";
fun ok: RE2 -> bool = "$1->ok()";
fun ProgramSize: RE2 -> int = "$1->ProgramSize()";
gen GlobalReplace: &string * RE2 * StringPiece -> int = "::re2::RE2::GlobalReplace($1, *$2, $3)";
gen Extract: StringPiece * RE2 * StringPiece * &string -> bool = "::re2::RE2::Extract($1, *$2, $3, $4)";
fun QuoteMeta: StringPiece -> string = "::re2::RE2::QuoteMeta($1)";
fun PossibleMatchRange: RE2 * &string * &string * int -> bool = "$1->PossibleMatchRange($2,$3,$3,$4)";
fun NumberOfCapturingGroups: RE2 -> int = "$1->NumberOfCapturingGroups()";
fun NamedCapturingGroups: RE2 -> Stl_Map::stl_map[string, int] = "$1->NamedCapturingGroups()";
// this function is fully general, just needs an anchor
gen Match: RE2 * StringPiece * int * Anchor * +StringPiece * int -> bool =
"$1->Match($2, $3, $2.length(),$4, $5, $6)"
;
noinline gen Match(re:RE2, var s:string) : opt[varray[string]] = {
var emptystring = "";
var n = NumberOfCapturingGroups re;
var v = varray[StringPiece] (n.size+1,StringPiece emptystring);
var Match-result = Match (re, StringPiece s, 0, ANCHOR_BOTH, v.stl_begin, n+1);
return
if Match-result then
Some$ map string of (StringPiece) v
else
None[varray[string]]
;
}
gen apply (re:RE2, s:string) => Match (re,s);
fun CheckRewriteString: RE2 * StringPiece * &string -> bool = "$1->CheckRewriteString($2, $3)";
instance Set[RE2, string] {
fun \in : string * RE2 -> bool =
"$2->Match(::re2::StringPiece($1),0, ::re2::StringPiece($1).length(),::re2::RE2::ANCHOR_BOTH, (::re2::StringPiece*)0, 0)"
;
}
gen iterator (re2:string, var target:string) => iterator (RE2 re2, target);
instance Iterable[RE2 * string, varray[string]] {
gen iterator (r:RE2, var target:string) () : opt[varray[string]] = {
var emptystring = "";
var l = len target;
var s = StringPiece target;
var p1 = s.data;
var p = 0;
var n = NumberOfCapturingGroups(r)+1;
var v1 = varray[StringPiece] (n.size,StringPiece emptystring);
var v2 = varray[string] (n.size,"");
again:>
var result = Match(r, s, p, UNANCHORED,v1.stl_begin, n);
if not result goto endoff;
for var i in 0 upto n - 1 do set(v2, i.size, string(v1.i)); done
var p2 = v1.0.data;
assert(v1.0.len.int > 0); // prevent infinite loop
p = (p2 - p1).int+v1.0.len.int;
yield Some v2;
goto again;
endoff:>
return None[varray[string]];
}
}
inherit Streamable[RE2 * string, Varray::varray[string]];
// Extract Some match array or None if not matching.
fun extract (re2:string, target:string) : opt[varray[string]] => iterator (RE2 re2, target) ();
fun extract (re2:RE2, target:string) : opt[varray[string]] => iterator (re2, target) ();
}
open Set[RE2, string];