// supported feature lists -----------------------------------------------------

supported_apis = ["record", "generic"];
supported_api_styles = ["free-form"];
supported_code_models = ["recursive-functions"];
supported_targets = ["code", "dot"];
supported_features = ["nested-ifs", "bitmaps", "monadic", "tags", "captvars"];


// language-specific options ---------------------------------------------------

semicolons = 0;
backtick_quoted_strings = 0;
single_quoted_strings = 0;
indentation_sensitive = 1;
wrap_blocks_in_braces = 0;
special_escapes = "\a\b\f\n\r\t\v\\'\"";


// immutable configurations (command-line only options) ------------------------

re2c:target = code;
re2c:code-model = recursive-functions;
re2c:input-encoding = ascii;
re2c:date = 1;
re2c:version = 1;
re2c:conditions = 0;
re2c:storable-state = 0;
re2c:flex-syntax = 0;
re2c:verbose = 0;
re2c:line-dirs = 1;


// mutable configurations ------------------------------------------------------

re2c:api = record;
re2c:api:style = free-form;
re2c:api:sigil = "@@";
re2c:YYGETCOND:naked = 0;
re2c:YYSETCOND:naked = 0;
re2c:YYSETCOND@cond = "@@";
re2c:YYGETSTATE:naked = 0;
re2c:YYSETSTATE:naked = 0;
re2c:YYSETSTATE@state = "@@";
re2c:YYFILL@len = "@@";
re2c:YYFILL:naked = 0;
re2c:YYFN = ["<undefined-function-name>;<undefined-function-type>"];
re2c:yyfn:sep = ";";
re2c:yyfn:throw = "";
re2c:yycond = "_yycond";
re2c:yyctable = ""; // unused
re2c:yyaccept = "_yyaccept";
re2c:yytarget = ""; // unused
re2c:yystate = "_yystate";
re2c:yynmatch = "yynmatch";
re2c:yypmatch = "yypmatch";
re2c:yyrecord = "yyrecord";
re2c:yych = "yych";
re2c:yych:conversion = 0;
re2c:yych:literals = hex;
re2c:yych:emit = (.code_model.recursive_functions ? 0 : 1);
re2c:yybm = "yybm";
re2c:yybm:hex = 0;
re2c:yystable = ""; // deprecated
re2c:header = "";
re2c:eof = -1;
re2c:sentinel = -1;
re2c:yyfill = "yyfill";
re2c:yyfill:enable = 1;
re2c:yyfill:parameter = 1;
re2c:yyfill:check = 1;
re2c:tags = 0;
re2c:tags:prefix = "_yyt";
re2c:captures = 0;
re2c:captvars = 0;
re2c:posix-captures = 0;
re2c:posix-captvars = 0;
re2c:invert-captures = 0;
re2c:cond:abort = 1;
re2c:cond:prefix = "yyc_";
re2c:cond:enumprefix = "YYC_";
re2c:cond:divider@cond = "@@";
re2c:cond:goto@cond = "@@";
re2c:state:abort = 1;
re2c:state:nextlabel = 0;
re2c:bit-vectors = 0;
re2c:debug-output = 0;
re2c:computed-gotos = 0;
re2c:computed-gotos:threshold = 9;
re2c:computed-gotos:relative = 0;
re2c:nested-ifs = 0;
re2c:case-insensitive = 0;
re2c:case-inverted = 0;
re2c:case-ranges = 0;
re2c:unsafe = 0;
re2c:monadic = 0;
re2c:encoding:ebcdic = 0;
re2c:encoding:utf32 = 0;
re2c:encoding:ucs2 = 0;
re2c:encoding:utf16 = 0;
re2c:encoding:utf8 = 0;
re2c:encoding-policy = ignore;
re2c:empty-class = match-empty;
re2c:indent:string = "    ";
re2c:indent:top = 0;
re2c:label:prefix = "yy"; // used for generating function names
re2c:label:yyfill = "";
re2c:label:yyloop = "";
re2c:label:yyNext = "";
re2c:label:start = 0;


// mutable code configuration --------------------------------------------------

re2c:YYBACKUP = "yybackup";
re2c:YYBACKUPCTX = "yybackupctx";
re2c:YYCONDTYPE = "YYCONDTYPE";
re2c:YYCOPYMTAG = "yycopymtag";
re2c:YYCOPYSTAG = "yycopystag";
re2c:YYCTYPE = "YYCTYPE";
re2c:YYCTXMARKER = "_yyctxmarker";
re2c:YYCURSOR = "_yycursor";
re2c:YYDEBUG = "yydebug";
re2c:YYEND = "yyend";
re2c:YYFILL = "yyfill";
re2c:YYGETACCEPT = "yygetaccept";
re2c:YYGETCOND = "yygetcond";
re2c:YYGETSTATE = "yygetstate";
re2c:YYINPUT = "_yyinput";
re2c:YYLESSTHAN = "yylessthan";
re2c:YYLIMIT = "_yylimit";
re2c:YYMARKER = "_yymarker";
re2c:YYMAXFILL = "yymaxfill";
re2c:YYMAXNMATCH = "yymaxnmatch";
re2c:YYMTAGN = "yymtagn";
re2c:YYMTAGP = "yymtagp";
re2c:YYPEEK = (.api.record ? "index" : "yypeek");
re2c:YYRESTORE = "yyrestore";
re2c:YYRESTORECTX = "yyrestorectx";
re2c:YYRESTORETAG = "yyrestoretag";
re2c:YYSETACCEPT = "yysetaccept";
re2c:YYSETCOND = "yysetcond";
re2c:YYSETSTATE = "yysetstate";
re2c:YYSHIFT = "yyshift";
re2c:YYSHIFTSTAG = "yyshiftstag";
re2c:YYSHIFTMTAG = "yyshiftmtag";
re2c:YYSKIP = "yyskip";
re2c:YYSTAGN = "yystagn";
re2c:YYSTAGP = "yystagp";
re2c:tags:expression = sigil;
re2c:tags:negative = (.api.generic ? "@@" : "(-1)");
re2c:cond:divider = "";
re2c:cond:goto = "";


// code templates --------------------------------------------------------------

code:var_local = topindent "let " name " = " init " in" nl;
code:var_global = topindent "let " name " = " init nl;

code:const_local = topindent "let " name " = " init " in" nl;
code:const_global = topindent name " = " init nl;

code:array_local = <undefined>;

code:array_global =
    topindent name " :: Array Int " type nl
    topindent name " = array (0, " size " - 1) $ Prelude.zip [0 .. " size " - 1] [" nl indent
        [row{0:-2}: topindent [elem{0:-2}: elem ", "] [elem{-1}: elem ","] nl]
        [row{-1}:   topindent [elem{0:-2}: elem ", "] [elem{-1}: elem "]"] nl];

code:array_elem = array " ! " index;

code:enum =
    "data " type " = "
        [elem{0:-2}: elem " | "]
        [elem{-1}: elem] " deriving (Eq, Show)"
    nl;

code:enum_elem = name;

code:assign = <undefined>;

code:type_int = <undefined>;
code:type_uint = <undefined>;
code:type_yybm = "Word8";
code:type_yytarget = <undefined>;
code:type_yyctable = <undefined>;

code:cmp_eq = "==";
code:cmp_ne = "/=";
code:cmp_lt = "<";
code:cmp_gt = ">";
code:cmp_le = "<=";
code:cmp_ge = ">=";

code:if_then_else =
    [branch{0}: topindent (.many ? "if " cond " then" : "when (" cond ") $") (.monadic ? " do") nl
        indent [stmt: stmt] dedent]
    [branch{1:-1}: topindent "else" (.cond ? " if " cond " then") (.monadic ? " do") nl
        indent [stmt: stmt] dedent];

code:if_then_else_oneline =
    [branch{0}: topindent (.many ? "if " cond " then " : "when (" cond ") $ ") [stmt: stmt] nl]
    [branch{1:-1}: topindent "else " (.cond ? "if " cond " then ") [stmt: stmt] nl];

code:switch =
    topindent "case " expr " of" nl
        indent [case: case] dedent;

code:switch_cases = topindent "_c | "
    [case{0:-2}: case " || "]
    [case{-1}:   case " ->" (.monadic ? " do") nl
        indent [stmt: stmt] dedent
    ];

code:switch_cases_oneline = <undefined>;

code:switch_case_range = (.many
    ? [val{0}: val] " <= _c && _c <= " [val{-1}: val]
    : [val{0}: val] " == _c");

code:switch_case_default = "True";

code:loop = <undefined>;
code:continue = <undefined>;
code:goto = <undefined>;
code:cgoto = <undefined>;
code:cgoto_data = <undefined>;

code:fndecl = <undefined>;

code:fndef =
    name " :: " [arg: argtype " -> "] type nl
    name [arg: " " argname] " =" (.monadic ? " do") nl
        indent [stmt: stmt] dedent;

code:fncall =
    topindent (.retval ? "let " retval " = ")
        name (.args ? [arg: " " arg] : " ()") nl;

code:tailcall = topindent name (.args ? [arg: " " arg] : " ()") nl;

code:recursive_functions = [fn: fndef nl];

code:fingerprint =
    "-- Generated by re2hs" (.version ? " " version) (.date ? " on " date) nl
    (.api.record ? "{-# LANGUAGE RecordWildCards #-}" nl);

code:line_info = "#" line " \"" file "\"" nl;

code:abort = topindent "error \"internal lexer error\"" nl;

code:yydebug = topindent YYDEBUG nl;

code:yypeek =
    topindent (.api.record
        ? (.monadic
            ? yych " <- return $ " YYPEEK " " YYINPUT " " YYCURSOR
            : "let " yych " = " YYPEEK " " YYINPUT " " YYCURSOR " in")
        : (.monadic
            ? yych " <- " YYPEEK
            : "let " yych " = " YYPEEK " in")
    ) nl;

code:yyskip =
    topindent (.api.record
        ? (.monadic
            ? YYCURSOR " <- return $ " YYCURSOR " + 1"
            : "let __ = " YYCURSOR " + 1 in let " YYCURSOR " = __ in")
        : YYSKIP
    ) nl;

code:yybackup =
    topindent (.api.record
        ? (.monadic
            ? "let " YYMARKER " = " YYCURSOR
            : "let " YYMARKER " = " YYCURSOR " in")
        : YYBACKUP
    ) nl;

code:yybackupctx =
    topindent (.api.record
        ? (.monadic
            ? "let " YYCTXMARKER " = " YYCURSOR
            : "let " YYCTXMARKER " = " YYCURSOR " in")
        : YYBACKUPCTX
    ) nl;

code:yyskip_yypeek = <undefined>;
code:yypeek_yyskip = <undefined>;
code:yyskip_yybackup = <undefined>;
code:yybackup_yyskip = <undefined>;
code:yybackup_yypeek = <undefined>;
code:yyskip_yybackup_yypeek = <undefined>;
code:yybackup_yypeek_yyskip = <undefined>;

code:yyrestore =
    topindent (.api.record
        ? (.monadic
            ? "let " YYCURSOR " = " YYMARKER
            : "let " YYCURSOR " = " YYMARKER " in")
        : YYRESTORE
    ) nl;

code:yyrestorectx =
    topindent (.api.record
        ? (.monadic
            ? "let " YYCURSOR " = " YYCTXMARKER
            : "let " YYCURSOR " = " YYCTXMARKER " in")
        : YYRESTORECTX
    ) nl;

code:yyrestoretag =
    topindent (.api.record
        ? (.monadic
            ? "let " YYCURSOR " = " tag
            : "let " YYCURSOR " = " tag " in")
        : YYRESTORETAG
    ) nl;

code:yyshift =
    topindent (.api.record
        ? (.monadic
            ? YYCURSOR " <- return $ " YYCURSOR " - " offset
            : "let __ = " YYCURSOR " - " offset " in let " YYCURSOR " = __ in")
        : YYSHIFT
    ) nl;

code:yyshiftstag =
    topindent (.api.record
        ? (.monadic
            ? tag " <- return $ if " tag " == " neg " then " neg " else " tag " - " offset
            :         "let __ = if " tag " == " neg " then " neg " else " tag " - " offset
                " in let " tag " = __ in")
        : YYSHIFTSTAG
    ) nl;

code:yyshiftmtag =
    topindent YYSHIFTMTAG nl;

code:yystagp =
    topindent (.api.record
        ? (.monadic
            ? "let " tag " = " YYCURSOR
            : "let " tag " = " YYCURSOR " in")
        : YYSTAGP
    ) nl;

code:yymtagp =
    topindent YYMTAGP nl;

code:yystagn =
    topindent (.api.record
        ? (.monadic
            ? "let " tag " = " neg
            : "let " tag " = " neg " in")
        : YYSTAGN
    ) nl;

code:yymtagn =
    topindent YYMTAGN nl;

code:yycopystag =
    topindent (.api.record
        ? (.monadic
            ? "let " lhs " = " rhs
            : "let " lhs " = " rhs " in")
        : YYCOPYSTAG
    ) nl;

code:yycopymtag =
    topindent (.api.record
        ? (.monadic
            ? "let " lhs " = " rhs
            : "let " lhs " = " rhs " in")
        : YYCOPYMTAG
    ) nl;

code:yygetaccept =
    (.api.record ? var : YYGETACCEPT);

code:yysetaccept =
    topindent (.api.record
        ? (.monadic
            ? "let " var " = " val
            : "let " var " = " val " in")
        : YYSETACCEPT
    ) nl;

code:yygetcond =
    (.api.record ? var : YYGETCOND);

code:yysetcond =
    topindent (.api.record
        ? (.monadic
            ? "let " var " = " val
            : "let " var " = " val " in")
        : YYSETCOND
    ) nl;

code:yygetstate =
    (.api.record ? var : YYGETSTATE);

code:yysetstate =
    topindent (.api.record
        ? (.monadic
            ? "let " var " = " val
            : "let " var " = " val " in")
        : YYSETSTATE
    ) nl;

code:yylessthan =
    (.api.record
        ? YYCURSOR " >= " YYLIMIT // YYFILL check can only be used with EOF rule $
        : YYLESSTHAN);

code:yyend =
    (.api.generic | .yyfill.enable
        ? YYEND
        : YYCURSOR " >= " YYLIMIT);

code:yybm_filter = "(" yych " .&. complement 0xFF) /= 0";

code:yybm_match = "(" yybm " ! (" offset " + fromIntegral " yych ") .&. " mask ") /= 0";

code:yytarget_filter = <undefined>;
