xquery version "1.0" encoding "UTF-8";

(: This file was generated on Fri Apr 18, 2025 11:03 (UTC+01) by REx v6.1 which is Copyright (c) 1979-2025 by Gunther Rademacher <grd@gmx.net> :)
(: REx command line: thymeleaf.ebnf -xquery -name Thyme -tree :)

(:~
 : The parser that was generated for the Thyme grammar.
 :)
module namespace p="Thyme";
declare default function namespace "http://www.w3.org/2005/xpath-functions";

(:~
 : The index of the lexer state for accessing the combined
 : (i.e. level > 1) lookahead code.
 :)
declare variable $p:lk as xs:integer := 1;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the begin of the token that has been consumed.
 :)
declare variable $p:b0 as xs:integer := 2;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the end of the token that has been consumed.
 :)
declare variable $p:e0 as xs:integer := 3;

(:~
 : The index of the lexer state for accessing the code of the
 : level-1-lookahead token.
 :)
declare variable $p:l1 as xs:integer := 4;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the begin of the level-1-lookahead token.
 :)
declare variable $p:b1 as xs:integer := 5;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the end of the level-1-lookahead token.
 :)
declare variable $p:e1 as xs:integer := 6;

(:~
 : The index of the lexer state for accessing the code of the
 : level-2-lookahead token.
 :)
declare variable $p:l2 as xs:integer := 7;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the begin of the level-2-lookahead token.
 :)
declare variable $p:b2 as xs:integer := 8;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the end of the level-2-lookahead token.
 :)
declare variable $p:e2 as xs:integer := 9;

(:~
 : The index of the lexer state for accessing the code of the
 : level-3-lookahead token.
 :)
declare variable $p:l3 as xs:integer := 10;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the begin of the level-3-lookahead token.
 :)
declare variable $p:b3 as xs:integer := 11;

(:~
 : The index of the lexer state for accessing the position in the
 : input string of the end of the level-3-lookahead token.
 :)
declare variable $p:e3 as xs:integer := 12;

(:~
 : The index of the lexer state for accessing the token code that
 : was expected when an error was found.
 :)
declare variable $p:error as xs:integer := 13;

(:~
 : The index of the lexer state that points to the first entry
 : used for collecting action results.
 :)
declare variable $p:result as xs:integer := 14;

(:~
 : The codepoint to charclass mapping for 7 bit codepoints.
 :)
declare variable $p:MAP0 as xs:integer+ :=
(
  42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 2, 2,
  6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 2, 2, 16, 2, 2, 17, 18, 18, 18, 18, 19,
  18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 2, 2, 20, 2, 21, 22, 23, 24,
  25, 18, 26, 18, 27, 28, 18, 29, 30, 31, 32, 33, 18, 34, 35, 36, 37, 18, 18, 18, 38, 18, 39, 2, 40, 41, 2
);

(:~
 : The codepoint to charclass mapping for codepoints below the surrogate block.
 :)
declare variable $p:MAP1 as xs:integer+ :=
(
  54, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
  58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 90, 122, 184, 216,
  152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
  152, 152, 152, 152, 152, 152, 152, 152, 152, 42, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 2, 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
  14, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 18,
  18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 2, 2, 20, 2,
  21, 22, 23, 24, 25, 18, 26, 18, 27, 28, 18, 29, 30, 31, 32, 33, 18, 34, 35, 36, 37, 18, 18, 18, 38, 18, 39, 2, 40, 41,
  2
);

(:~
 : The codepoint to charclass mapping for codepoints above the surrogate block.
 :)
declare variable $p:MAP2 as xs:integer+ :=
(
  57344, 65536, 65533, 1114111, 2, 2
);

(:~
 : The token-set-id to DFA-initial-state mapping.
 :)
declare variable $p:INITIAL as xs:integer+ :=
(
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
);

(:~
 : The DFA transition table.
 :)
declare variable $p:TRANSITION as xs:integer+ :=
(
  717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 688, 688, 694, 717, 704, 717, 851,
  1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 704, 717, 851, 1112, 717, 717, 717, 717, 717, 717,
  717, 717, 717, 718, 716, 717, 726, 717, 1115, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 696, 738, 717, 704,
  717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 739, 747, 717, 704, 717, 851, 1112, 717, 717, 717, 717,
  717, 717, 717, 717, 717, 748, 707, 717, 756, 717, 872, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1148, 827, 1151,
  717, 704, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1058, 768, 771, 717, 704, 717, 851, 1112, 717, 717,
  717, 717, 717, 717, 717, 717, 717, 708, 784, 717, 704, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717,
  717, 717, 717, 704, 717, 851, 793, 717, 717, 717, 717, 717, 717, 717, 717, 717, 1035, 717, 717, 704, 717, 851, 1112,
  717, 717, 717, 717, 717, 717, 717, 717, 717, 886, 717, 887, 704, 717, 851, 793, 717, 717, 717, 717, 717, 717, 717,
  717, 904, 804, 811, 796, 820, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 886, 717, 887, 704, 717,
  851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 835, 849, 1211, 843, 717, 760, 859, 1018, 717, 717, 717, 717,
  717, 717, 717, 986, 717, 717, 717, 704, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 717, 1152, 870, 717,
  704, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1257, 880, 717, 1005, 704, 717, 760, 1112, 717, 717, 717,
  717, 717, 717, 717, 717, 1257, 880, 717, 1005, 895, 717, 760, 901, 717, 717, 717, 717, 717, 717, 717, 717, 1257, 1258,
  717, 948, 704, 717, 760, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 944, 880, 730, 912, 704, 717, 760, 1207, 717,
  958, 717, 717, 717, 717, 717, 717, 1001, 880, 717, 1092, 704, 717, 760, 1129, 717, 717, 717, 717, 717, 717, 717, 717,
  1054, 880, 717, 1005, 704, 717, 760, 1112, 717, 920, 717, 717, 717, 717, 717, 717, 1175, 880, 773, 1005, 704, 717,
  760, 1112, 717, 1238, 717, 717, 717, 717, 717, 717, 1257, 880, 717, 1185, 895, 717, 760, 930, 956, 717, 717, 717, 717,
  717, 717, 717, 1257, 880, 717, 1005, 704, 717, 760, 1112, 717, 775, 717, 717, 717, 717, 717, 717, 966, 880, 785, 1005,
  704, 717, 760, 1112, 984, 717, 717, 717, 717, 717, 717, 717, 1257, 880, 717, 1005, 704, 717, 994, 1112, 717, 717, 717,
  717, 717, 717, 717, 717, 1013, 880, 717, 1005, 704, 971, 760, 1143, 717, 717, 717, 717, 717, 717, 717, 717, 1030, 880,
  717, 1005, 704, 717, 1047, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1066, 880, 717, 1005, 704, 717, 760, 1112,
  922, 1086, 717, 717, 717, 717, 717, 717, 1100, 880, 1180, 1005, 704, 1106, 760, 1112, 717, 717, 717, 717, 717, 717,
  717, 717, 1257, 880, 717, 1005, 704, 772, 760, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1257, 880, 1072, 1005,
  704, 1123, 976, 1112, 717, 776, 717, 717, 717, 717, 717, 717, 1137, 880, 717, 1005, 704, 862, 760, 1112, 717, 717,
  717, 717, 717, 717, 717, 717, 1257, 880, 717, 1243, 704, 1039, 1078, 1112, 717, 717, 717, 717, 717, 717, 717, 717,
  1257, 880, 717, 1160, 704, 717, 760, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1257, 880, 717, 1005, 704, 717,
  760, 1112, 774, 717, 717, 717, 717, 717, 717, 717, 717, 1168, 717, 717, 1193, 1201, 851, 1112, 717, 717, 717, 717,
  717, 717, 717, 717, 812, 937, 717, 717, 704, 717, 1022, 1112, 1232, 717, 717, 717, 717, 717, 717, 717, 717, 1219,
  1226, 887, 704, 717, 851, 1112, 717, 717, 717, 717, 717, 717, 717, 717, 1251, 717, 717, 717, 717, 717, 717, 717, 717,
  717, 717, 717, 717, 717, 717, 717, 274, 274, 274, 274, 274, 274, 274, 274, 0, 0, 0, 0, 0, 0, 32, 1954, 33, 0, 0, 36,
  0, 0, 0, 0, 0, 0, 0, 37, 33, 0, 0, 0, 0, 0, 0, 0, 0, 33, 1590, 0, 0, 36, 0, 0, 0, 0, 44, 45, 0, 0, 1954, 0, 0, 0, 0,
  0, 0, 0, 35, 35, 0, 0, 0, 0, 0, 0, 0, 36, 33, 0, 0, 1592, 0, 0, 0, 0, 53, 0, 67, 0, 0, 2304, 0, 2304, 0, 0, 0, 0, 0,
  0, 0, 46, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 47, 0, 68, 69, 0, 0, 0, 0, 0, 542, 0, 800, 542, 0, 0, 0, 2688, 2688,
  542, 38, 0, 0, 0, 0, 0, 0, 0, 3072, 33, 0, 0, 36, 0, 0, 1337, 0, 0, 2176, 0, 0, 2176, 2176, 2176, 542, 0, 0, 0, 0, 0,
  542, 1191, 33, 0, 0, 36, 0, 1337, 1191, 0, 0, 0, 0, 0, 0, 0, 67, 0, 1337, 1476, 69, 0, 0, 0, 0, 0, 1664, 51, 0, 40, 0,
  0, 0, 0, 0, 0, 0, 67, 36, 542, 1821, 0, 0, 0, 0, 542, 0, 0, 0, 0, 0, 542, 0, 0, 33, 0, 0, 36, 0, 0, 58, 0, 69, 0, 0,
  0, 0, 0, 2688, 0, 0, 48, 0, 0, 0, 1821, 542, 53, 800, 51, 0, 0, 0, 0, 0, 0, 0, 75, 0, 58, 0, 69, 0, 0, 71, 46, 0, 0,
  3072, 0, 3072, 3072, 3072, 0, 19, 1821, 0, 0, 0, 0, 0, 1821, 0, 53, 800, 73, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0, 23, 1821,
  0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 66, 53, 0, 67, 0, 0, 74, 0, 0, 0, 0, 0, 0, 2816, 0, 0, 65, 0, 0, 53, 0, 67, 0, 20,
  1821, 0, 0, 0, 0, 0, 1821, 542, 53, 800, 0, 24, 1821, 0, 0, 0, 0, 0, 1476, 0, 0, 0, 0, 640, 0, 67, 0, 0, 25, 1821, 0,
  0, 0, 0, 0, 2560, 0, 0, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 53, 0, 67, 0, 21, 1821, 0, 0, 0, 0, 0, 2304, 0, 0, 0, 0, 26,
  1821, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 46, 0, 53, 0, 67, 0, 0, 77, 0, 0, 0, 0, 0, 0, 50, 0, 1821, 542, 53, 800, 0,
  27, 1821, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 33, 67, 0, 0, 60, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 72,
  0, 28, 1821, 0, 0, 0, 0, 0, 69, 0, 46, 0, 0, 0, 2176, 0, 0, 0, 0, 0, 0, 0, 40, 0, 49, 0, 0, 1821, 542, 53, 800, 31, 0,
  0, 0, 0, 0, 31, 0, 22, 1821, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 51, 1821, 542, 53, 800, 33, 55, 2048, 36, 2432, 0, 0,
  2944, 59, 0, 0, 0, 0, 0, 0, 0, 69, 70, 0, 0, 0, 0, 1821, 542, 0, 800, 542, 0, 0, 0, 0, 0, 542, 41, 0, 0, 0, 0, 0, 0,
  0, 384, 0, 896, 0, 0, 0, 78, 0, 0, 0, 0, 0, 52, 1821, 542, 53, 800, 1024, 0, 0, 0, 0, 0, 0, 0, 1821, 0, 0, 0, 0, 0, 0
);

(:~
 : The DFA-state to expected-token-set mapping.
 :)
declare variable $p:EXPECTED as xs:integer+ :=
(
  20, 24, 28, 32, 36, 60, 60, 42, 53, 46, 59, 60, 60, 50, 57, 60, 38, 59, 60, 38, 130, 4098, 8194, 65538, 131074,
  1048578, 2097154, 8388610, 26, 139266, 8454146, 655362, 9437186, 9502722, 8454202, 4575046, 4706118, 2, 4096, 4096, 4,
  1024, 8192, 8, 16, 32, 262144, 1536, 1792, 4194304, 16, 2048, 4, 2048, 4, 32768, 2048, 1536, 1024, 64, 4096, 4096,
  4096, 4096
);

(:~
 : The token-string table.
 :)
declare variable $p:TOKEN as xs:string+ :=
(
  "%ERROR",
  "Whitespace",
  "MessageExpression",
  "UrlFrag",
  "UrlVar",
  "Hash",
  "FragmentExpression",
  "EOF",
  "IntegerLiteral",
  "DecimalLiteral",
  "DoubleLiteral",
  "StringLiteral",
  "UtilityObject",
  "Identifier",
  "'#'",
  "'${'",
  "'('",
  "')'",
  "'*{'",
  "','",
  "'.'",
  "'='",
  "'@{'",
  "'}'"
);

(:~
 : Match next token in input string, starting at given index, using
 : the DFA entry state for the set of tokens that are expected in
 : the current context.
 :
 : @param $input the input string.
 : @param $begin the index where to start in input string.
 : @param $token-set the expected token set id.
 : @return a sequence of three: the token code of the result token,
 : with input string begin and end positions. If there is no valid
 : token, return the negative id of the DFA state that failed, along
 : with begin and end positions of the longest viable prefix.
 :)
declare function p:match($input as xs:string,
                         $begin as xs:integer,
                         $token-set as xs:integer) as xs:integer+
{
  let $result := $p:INITIAL[1 + $token-set]
  return p:transition($input,
                      $begin,
                      $begin,
                      $begin,
                      $result,
                      $result mod 128,
                      0)
};

(:~
 : The DFA state transition function. If we are in a valid DFA state, save
 : it's result annotation, consume one input codepoint, calculate the next
 : state, and use tail recursion to do the same again. Otherwise, return
 : any valid result or a negative DFA state id in case of an error.
 :
 : @param $input the input string.
 : @param $begin the begin index of the current token in the input string.
 : @param $current the index of the current position in the input string.
 : @param $end the end index of the result in the input string.
 : @param $result the result code.
 : @param $current-state the current DFA state.
 : @param $previous-state the  previous DFA state.
 : @return a sequence of three: the token code of the result token,
 : with input string begin and end positions. If there is no valid
 : token, return the negative id of the DFA state that failed, along
 : with begin and end positions of the longest viable prefix.
 :)
declare function p:transition($input as xs:string,
                              $begin as xs:integer,
                              $current as xs:integer,
                              $end as xs:integer,
                              $result as xs:integer,
                              $current-state as xs:integer,
                              $previous-state as xs:integer)
{
  if ($current-state eq 0) then
    let $result := $result idiv 128
    let $end := if ($end gt string-length($input)) then string-length($input) + 1 else $end
    return
      if ($result ne 0) then
      (
        $result - 1,
        $begin,
        $end
      )
      else
      (
        - $previous-state,
        $begin,
        $current - 1
      )
  else
    let $c0 := (string-to-codepoints(substring($input, $current, 1)), 0)[1]
    let $c1 :=
      if ($c0 < 128) then
        $p:MAP0[1 + $c0]
      else if ($c0 < 55296) then
        let $c1 := $c0 idiv 32
        let $c2 := $c1 idiv 32
        return $p:MAP1[1 + $c0 mod 32 + $p:MAP1[1 + $c1 mod 32 + $p:MAP1[1 + $c2]]]
      else
        p:map2($c0, 1, 2)
    let $current := $current + 1
    let $i0 := 128 * $c1 + $current-state - 1
    let $i1 := $i0 idiv 8
    let $next-state := $p:TRANSITION[$i0 mod 8 + $p:TRANSITION[$i1 + 1] + 1]
    return
      if ($next-state > 127) then
        p:transition($input, $begin, $current, $current, $next-state, $next-state mod 128, $current-state)
      else
        p:transition($input, $begin, $current, $end, $result, $next-state, $current-state)
};

(:~
 : Recursively translate one 32-bit chunk of an expected token bitset
 : to the corresponding sequence of token strings.
 :
 : @param $result the result of previous recursion levels.
 : @param $chunk the 32-bit chunk of the expected token bitset.
 : @param $base-token-code the token code of bit 0 in the current chunk.
 : @return the set of token strings.
 :)
declare function p:token($result as xs:string*,
                         $chunk as xs:integer,
                         $base-token-code as xs:integer)
{
  if ($chunk = 0) then
    $result
  else
    p:token
    (
      ($result, if ($chunk mod 2 != 0) then $p:TOKEN[$base-token-code] else ()),
      if ($chunk < 0) then $chunk idiv 2 + 2147483648 else $chunk idiv 2,
      $base-token-code + 1
    )
};

(:~
 : Calculate expected token set for a given DFA state as a sequence
 : of strings.
 :
 : @param $state the DFA state.
 : @return the set of token strings.
 :)
declare function p:expected-token-set($state as xs:integer) as xs:string*
{
  if ($state > 0) then
    for $t in 0 to 0
    let $i0 := $t * 78 + $state - 1
    let $i1 := $i0 idiv 4
    return p:token((), $p:EXPECTED[$i0 mod 4 + $p:EXPECTED[$i1 + 1] + 1], $t * 32 + 1)
  else
    ()
};

(:~
 : Classify codepoint by doing a tail recursive binary search for a
 : matching codepoint range entry in MAP2, the codepoint to charclass
 : map for codepoints above the surrogate block.
 :
 : @param $c the codepoint.
 : @param $lo the binary search lower bound map index.
 : @param $hi the binary search upper bound map index.
 : @return the character class.
 :)
declare function p:map2($c as xs:integer, $lo as xs:integer, $hi as xs:integer) as xs:integer
{
  if ($lo > $hi) then
    0
  else
    let $m := ($hi + $lo) idiv 2
    return
      if ($p:MAP2[$m] > $c) then
        p:map2($c, $lo, $m - 1)
      else if ($p:MAP2[2 + $m] < $c) then
        p:map2($c, $m + 1, $hi)
      else
        $p:MAP2[4 + $m]
};

(:~
 : Parse NumericLiteral.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-NumericLiteral($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 8) then                        (: IntegerLiteral :)
      let $state := p:consume(8, $input, $state)            (: IntegerLiteral :)
      return $state
    else if ($state[$p:l1] = 9) then                        (: DecimalLiteral :)
      let $state := p:consume(9, $input, $state)            (: DecimalLiteral :)
      return $state
    else
      let $state := p:consume(10, $input, $state)           (: DoubleLiteral :)
      return $state
  let $end := $state[$p:e0]
  return p:reduce($state, "NumericLiteral", $count, $begin, $end)
};

(:~
 : Parse Literal.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-Literal($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 11) then                       (: StringLiteral :)
      let $state := p:consume(11, $input, $state)           (: StringLiteral :)
      return $state
    else
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-NumericLiteral($input, $state)
      return $state
  let $end := $state[$p:e0]
  return p:reduce($state, "Literal", $count, $begin, $end)
};

(:~
 : Parse UtilityExpression.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-UtilityExpression($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(14, $input, $state)               (: '#' :)
  let $state := p:lookahead1W(1, $input, $state)            (: Whitespace | UtilityObject :)
  let $state := p:consume(12, $input, $state)               (: UtilityObject :)
  let $state := p:lookahead1W(5, $input, $state)            (: Whitespace | '.' :)
  let $state := p:consume(20, $input, $state)               (: '.' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "UtilityExpression", $count, $begin, $end)
};

(:~
 : Parse UrlParameter.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-UrlParameter($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(13, $input, $state)               (: Identifier :)
  let $state := p:lookahead1W(6, $input, $state)            (: Whitespace | '=' :)
  let $state := p:consume(21, $input, $state)               (: '=' :)
  let $state := p:lookahead1W(15, $input, $state)           (: Whitespace | MessageExpression | FragmentExpression |
                                                               IntegerLiteral | DecimalLiteral | DoubleLiteral |
                                                               StringLiteral | '#' | '${' | '(' | '*{' | '@{' :)
  let $state := p:whitespace($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-Expression($input, $state)
  let $end := $state[$p:e0]
  return p:reduce($state, "UrlParameter", $count, $begin, $end)
};

(:~
 : Parse the 1st loop of production UrlParameters (zero or more). Use
 : tail recursion for iteratively updating the lexer state.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-UrlParameters-1($input as xs:string, $state as item()+)
{
  if ($state[$p:error]) then
    $state
  else
    let $state := p:lookahead1W(11, $input, $state)         (: Whitespace | ')' | ',' :)
    return
      if ($state[$p:l1] != 19) then                         (: ',' :)
        $state
      else
        let $state := p:consume(19, $input, $state)         (: ',' :)
        let $state := p:lookahead1W(2, $input, $state)      (: Whitespace | Identifier :)
        let $state := p:whitespace($input, $state)
        let $state :=
          if ($state[$p:error]) then
            $state
          else
            p:parse-UrlParameter($input, $state)
        return p:parse-UrlParameters-1($input, $state)
};

(:~
 : Parse UrlParameters.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-UrlParameters($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(16, $input, $state)               (: '(' :)
  let $state := p:lookahead1W(9, $input, $state)            (: Whitespace | Identifier | ')' :)
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 13) then                       (: Identifier :)
      let $state := p:whitespace($input, $state)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-UrlParameter($input, $state)
      let $state := p:parse-UrlParameters-1($input, $state)
      return $state
    else
      $state
  let $state := p:consume(17, $input, $state)               (: ')' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "UrlParameters", $count, $begin, $end)
};

(:~
 : Parse the 1st loop of production LinkExpression (one or more). Use
 : tail recursion for iteratively updating the lexer state.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-LinkExpression-1($input as xs:string, $state as item()+)
{
  if ($state[$p:error]) then
    $state
  else
    let $state := p:lookahead1W(8, $input, $state)          (: Whitespace | UrlFrag | UrlVar :)
    let $state :=
      if ($state[$p:error]) then
        $state
      else if ($state[$p:l1] = 3) then                      (: UrlFrag :)
        let $state := p:consume(3, $input, $state)          (: UrlFrag :)
        return $state
      else
        let $state := p:consume(4, $input, $state)          (: UrlVar :)
        return $state
    let $state := p:lookahead1W(14, $input, $state)         (: Whitespace | UrlFrag | UrlVar | Hash | '(' | '}' :)
    return
      if ($state[$p:l1] != 3                                (: UrlFrag :)
      and $state[$p:l1] != 4) then                          (: UrlVar :)
        $state
      else
        p:parse-LinkExpression-1($input, $state)
};

(:~
 : Parse LinkExpression.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-LinkExpression($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(22, $input, $state)               (: '@{' :)
  let $state := p:parse-LinkExpression-1($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 5) then                        (: Hash :)
      let $state := p:consume(5, $input, $state)            (: Hash :)
      return $state
    else
      $state
  let $state := p:lookahead1W(10, $input, $state)           (: Whitespace | '(' | '}' :)
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 16) then                       (: '(' :)
      let $state := p:whitespace($input, $state)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-UrlParameters($input, $state)
      return $state
    else
      $state
  let $state := p:lookahead1W(7, $input, $state)            (: Whitespace | '}' :)
  let $state := p:consume(23, $input, $state)               (: '}' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "LinkExpression", $count, $begin, $end)
};

(:~
 : Parse SelectionExpression.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-SelectionExpression($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(18, $input, $state)               (: '*{' :)
  let $state := p:lookahead1W(2, $input, $state)            (: Whitespace | Identifier :)
  let $state := p:whitespace($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-ObjectAccess($input, $state)
  let $state := p:consume(23, $input, $state)               (: '}' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "SelectionExpression", $count, $begin, $end)
};

(:~
 : Parse Argument.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-Argument($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-Expression($input, $state)
  let $end := $state[$p:e0]
  return p:reduce($state, "Argument", $count, $begin, $end)
};

(:~
 : Parse MethodName.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-MethodName($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(13, $input, $state)               (: Identifier :)
  let $end := $state[$p:e0]
  return p:reduce($state, "MethodName", $count, $begin, $end)
};

(:~
 : Parse the 1st loop of production MethodInvocation (zero or more). Use
 : tail recursion for iteratively updating the lexer state.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-MethodInvocation-1($input as xs:string, $state as item()+)
{
  if ($state[$p:error]) then
    $state
  else
    let $state := p:lookahead1W(11, $input, $state)         (: Whitespace | ')' | ',' :)
    return
      if ($state[$p:l1] != 19) then                         (: ',' :)
        $state
      else
        let $state := p:consume(19, $input, $state)         (: ',' :)
        let $state := p:lookahead1W(15, $input, $state)     (: Whitespace | MessageExpression | FragmentExpression |
                                                               IntegerLiteral | DecimalLiteral | DoubleLiteral |
                                                               StringLiteral | '#' | '${' | '(' | '*{' | '@{' :)
        let $state := p:whitespace($input, $state)
        let $state :=
          if ($state[$p:error]) then
            $state
          else
            p:parse-Argument($input, $state)
        return p:parse-MethodInvocation-1($input, $state)
};

(:~
 : Parse MethodInvocation.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-MethodInvocation($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(20, $input, $state)               (: '.' :)
  let $state := p:lookahead1W(2, $input, $state)            (: Whitespace | Identifier :)
  let $state := p:whitespace($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-MethodName($input, $state)
  let $state := p:lookahead1W(3, $input, $state)            (: Whitespace | '(' :)
  let $state := p:consume(16, $input, $state)               (: '(' :)
  let $state := p:lookahead1W(16, $input, $state)           (: Whitespace | MessageExpression | FragmentExpression |
                                                               IntegerLiteral | DecimalLiteral | DoubleLiteral |
                                                               StringLiteral | '#' | '${' | '(' | ')' | '*{' | '@{' :)
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] != 17) then                      (: ')' :)
      let $state := p:whitespace($input, $state)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-Argument($input, $state)
      let $state := p:parse-MethodInvocation-1($input, $state)
      return $state
    else
      $state
  let $state := p:consume(17, $input, $state)               (: ')' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "MethodInvocation", $count, $begin, $end)
};

(:~
 : Parse Property.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-Property($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(13, $input, $state)               (: Identifier :)
  let $end := $state[$p:e0]
  return p:reduce($state, "Property", $count, $begin, $end)
};

(:~
 : Parse Variable.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-Variable($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(13, $input, $state)               (: Identifier :)
  let $end := $state[$p:e0]
  return p:reduce($state, "Variable", $count, $begin, $end)
};

(:~
 : Parse the 1st loop of production ObjectAccess (zero or more). Use
 : tail recursion for iteratively updating the lexer state.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-ObjectAccess-1($input as xs:string, $state as item()+)
{
  if ($state[$p:error]) then
    $state
  else
    let $state := p:lookahead1W(12, $input, $state)         (: Whitespace | '.' | '}' :)
    let $state :=
      if ($state[$p:l1] eq 20) then                         (: '.' :)
        let $state := p:lookahead2W(2, $input, $state)      (: Whitespace | Identifier :)
        let $state :=
          if ($state[$p:lk] eq 436) then                    (: '.' Identifier :)
            let $state := p:lookahead3W(13, $input, $state) (: Whitespace | '(' | '.' | '}' :)
            return $state
          else
            $state
        return $state
      else
        ($state[$p:l1], subsequence($state, $p:lk + 1))
    return
      if ($state[$p:lk] != 20916                            (: '.' Identifier '.' :)
      and $state[$p:lk] != 23988) then                      (: '.' Identifier '}' :)
        $state
      else
        let $state := p:consume(20, $input, $state)         (: '.' :)
        let $state := p:lookahead1W(2, $input, $state)      (: Whitespace | Identifier :)
        let $state := p:whitespace($input, $state)
        let $state :=
          if ($state[$p:error]) then
            $state
          else
            p:parse-Property($input, $state)
        return p:parse-ObjectAccess-1($input, $state)
};

(:~
 : Parse the 2nd loop of production ObjectAccess (zero or more). Use
 : tail recursion for iteratively updating the lexer state.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-ObjectAccess-2($input as xs:string, $state as item()+)
{
  if ($state[$p:error]) then
    $state
  else
    let $state := p:lookahead1W(12, $input, $state)         (: Whitespace | '.' | '}' :)
    return
      if ($state[$p:l1] != 20) then                         (: '.' :)
        $state
      else
        let $state := p:whitespace($input, $state)
        let $state :=
          if ($state[$p:error]) then
            $state
          else
            p:parse-MethodInvocation($input, $state)
        return p:parse-ObjectAccess-2($input, $state)
};

(:~
 : Parse ObjectAccess.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-ObjectAccess($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-Variable($input, $state)
  let $state := p:parse-ObjectAccess-1($input, $state)
  let $state := p:parse-ObjectAccess-2($input, $state)
  let $end := $state[$p:e0]
  return p:reduce($state, "ObjectAccess", $count, $begin, $end)
};

(:~
 : Parse VariableExpression.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-VariableExpression($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:consume(15, $input, $state)               (: '${' :)
  let $state := p:lookahead1W(2, $input, $state)            (: Whitespace | Identifier :)
  let $state := p:whitespace($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-ObjectAccess($input, $state)
  let $state := p:consume(23, $input, $state)               (: '}' :)
  let $end := $state[$p:e0]
  return p:reduce($state, "VariableExpression", $count, $begin, $end)
};

(:~
 : Parse Expression.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-Expression($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state :=
    if ($state[$p:error]) then
      $state
    else if ($state[$p:l1] = 15) then                       (: '${' :)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-VariableExpression($input, $state)
      return $state
    else if ($state[$p:l1] = 18) then                       (: '*{' :)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-SelectionExpression($input, $state)
      return $state
    else if ($state[$p:l1] = 2) then                        (: MessageExpression :)
      let $state := p:consume(2, $input, $state)            (: MessageExpression :)
      return $state
    else if ($state[$p:l1] = 22) then                       (: '@{' :)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-LinkExpression($input, $state)
      return $state
    else if ($state[$p:l1] = 6) then                        (: FragmentExpression :)
      let $state := p:consume(6, $input, $state)            (: FragmentExpression :)
      return $state
    else if ($state[$p:l1] = 14) then                       (: '#' :)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-UtilityExpression($input, $state)
      return $state
    else if ($state[$p:l1] = 16) then                       (: '(' :)
      let $state := p:consume(16, $input, $state)           (: '(' :)
      let $state := p:lookahead1W(15, $input, $state)       (: Whitespace | MessageExpression | FragmentExpression |
                                                               IntegerLiteral | DecimalLiteral | DoubleLiteral |
                                                               StringLiteral | '#' | '${' | '(' | '*{' | '@{' :)
      let $state := p:whitespace($input, $state)
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-Expression($input, $state)
      let $state := p:lookahead1W(4, $input, $state)        (: Whitespace | ')' :)
      let $state := p:consume(17, $input, $state)           (: ')' :)
      return $state
    else
      let $state :=
        if ($state[$p:error]) then
          $state
        else
          p:parse-Literal($input, $state)
      return $state
  let $end := $state[$p:e0]
  return p:reduce($state, "Expression", $count, $begin, $end)
};

(:~
 : Parse ThymeLeaf.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:parse-ThymeLeaf($input as xs:string, $state as item()+) as item()+
{
  let $count := count($state)
  let $begin := $state[$p:e0]
  let $state := p:lookahead1W(15, $input, $state)           (: Whitespace | MessageExpression | FragmentExpression |
                                                               IntegerLiteral | DecimalLiteral | DoubleLiteral |
                                                               StringLiteral | '#' | '${' | '(' | '*{' | '@{' :)
  let $state := p:whitespace($input, $state)
  let $state :=
    if ($state[$p:error]) then
      $state
    else
      p:parse-Expression($input, $state)
  let $state := p:lookahead1W(0, $input, $state)            (: Whitespace | EOF :)
  let $state := p:consume(7, $input, $state)                (: EOF :)
  let $end := $state[$p:e0]
  return p:reduce($state, "ThymeLeaf", $count, $begin, $end)
};

(:~
 : Create a textual error message from a parsing error.
 :
 : @param $input the input string.
 : @param $error the parsing error descriptor.
 : @return the error message.
 :)
declare function p:error-message($input as xs:string, $error as element(error)) as xs:string
{
  let $begin := xs:integer($error/@b)
  let $context := string-to-codepoints(substring($input, 1, $begin - 1))
  let $linefeeds := index-of($context, 10)
  let $line := count($linefeeds) + 1
  let $column := ($begin - $linefeeds[last()], $begin)[1]
  return
    string-join
    (
      (
        if ($error/@o) then
          ("syntax error, found ", $p:TOKEN[$error/@o + 1])
        else
          "lexical analysis failed",
        "&#10;",
        "while expecting ",
        if ($error/@x) then
          $p:TOKEN[$error/@x + 1]
        else
          let $expected := p:expected-token-set($error/@s)
          return
          (
            "["[exists($expected[2])],
            string-join($expected, ", "),
            "]"[exists($expected[2])]
          ),
        "&#10;",
        if ($error/@o or $error/@e = $begin) then
          ()
        else
          ("after successfully scanning ", string($error/@e - $begin), " characters beginning "),
        "at line ", string($line), ", column ", string($column), ":&#10;",
        "...", substring($input, $begin, 64), "..."
      ),
      ""
    )
};

(:~
 : Consume one token, i.e. compare lookahead token 1 with expected
 : token and in case of a match, shift lookahead tokens down such that
 : l1 becomes the current token, and higher lookahead tokens move down.
 : When lookahead token 1 does not match the expected token, raise an
 : error by saving the expected token code in the error field of the
 : lexer state.
 :
 : @param $code the expected token.
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:consume($code as xs:integer, $input as xs:string, $state as item()+) as item()+
{
  if ($state[$p:error]) then
    $state
  else if ($state[$p:l1] eq $code) then
  (
    subsequence($state, $p:l1, 9),
    0, 0, 0,
    subsequence($state, 13),
    let $begin := $state[$p:e0]
    let $end := $state[$p:b1]
    where $begin ne $end
    return
      text
      {
        substring($input, $begin, $end - $begin)
      },
    let $token := $p:TOKEN[1 + $state[$p:l1]]
    let $name := if (starts-with($token, "'")) then "TOKEN" else $token
    let $begin := $state[$p:b1]
    let $end := $state[$p:e1]
    return
      element {$name}
      {
        substring($input, $begin, $end - $begin)
      }
  )
  else
  (
    subsequence($state, 1, $p:error - 1),
    element error
    {
      attribute b {$state[$p:b1]},
      attribute e {$state[$p:e1]},
      if ($state[$p:l1] lt 0) then
        attribute s {- $state[$p:l1]}
      else
        (attribute o {$state[$p:l1]}, attribute x {$code})
    },
    subsequence($state, $p:error + 1)
  )
};

(:~
 : Consume whitespace.
 :
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:whitespace($input as xs:string,
                              $state as item()+) as item()+
{
  if ($state[$p:e0] = $state[$p:b1]) then
    $state
  else
    let $begin := $state[$p:e0]
    let $end := $state[$p:b1]
    return
    (
      0,
      $state[$p:b0],
      $end,
      subsequence($state, $p:e0 + 1),
      text
      {
        substring($input, $begin, $end - $begin)
      }
    )
};

(:~
 : Use p:match to fetch the next token, but skip any leading
 : whitespace.
 :
 : @param $input the input string.
 : @param $begin the index where to start.
 : @param $token-set the valid token set id.
 : @return a sequence of three values: the token code of the result
 : token, with input string positions of token begin and end.
 :)
declare function p:matchW($input as xs:string,
                          $begin as xs:integer,
                          $token-set as xs:integer)
{
  let $match := p:match($input, $begin, $token-set)
  return
    if ($match[1] = 1) then                                 (: Whitespace :)
      p:matchW($input, $match[3], $token-set)
    else
      $match
};

(:~
 : Lookahead one token on level 1 with whitespace skipping.
 :
 : @param $set the code of the DFA entry state for the set of valid tokens.
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:lookahead1W($set as xs:integer, $input as xs:string, $state as item()+) as item()+
{
  if ($state[$p:l1] ne 0) then
    $state
  else
    let $match :=
      (
        p:matchW($input, $state[$p:e0], $set),
        0, 0, 0
      )
    return
    (
      $match[1],
      subsequence($state, $p:b0, 2),
      $match,
      subsequence($state, 10)
    )
};

(:~
 : Lookahead one token on level 2 with whitespace skipping.
 :
 : @param $set the code of the DFA entry state for the set of valid tokens.
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:lookahead2W($set as xs:integer, $input as xs:string, $state as item()+) as item()+
{
  let $match :=
    if ($state[$p:l2] ne 0) then
      subsequence($state, $p:l2, 6)
    else
    (
      p:matchW($input, $state[$p:e1], $set),
      0, 0, 0
    )
  return
  (
    $match[1] * 32 + $state[$p:l1],
    subsequence($state, $p:b0, 5),
    $match,
    subsequence($state, 13)
  )
};

(:~
 : Lookahead one token on level 3 with whitespace skipping.
 :
 : @param $set the code of the DFA entry state for the set of valid tokens.
 : @param $input the input string.
 : @param $state lexer state, error indicator, and result stack.
 : @return the updated state.
 :)
declare function p:lookahead3W($set as xs:integer, $input as xs:string, $state as item()+) as item()+
{
  let $match :=
    if ($state[$p:l3] ne 0) then
      subsequence($state, $p:l3, 3)
    else
      p:matchW($input, $state[$p:e2], $set)
  return
  (
    $match[1] * 1024 + $state[$p:lk],
    subsequence($state, $p:b0, 8),
    $match,
    subsequence($state, 13)
  )
};

(:~
 : Reduce the result stack, creating a nonterminal element. Pop
 : $count elements off the stack, wrap them in a new element
 : named $name, and push the new element.
 :
 : @param $state lexer state, error indicator, and result stack.
 : @param $name the name of the result node.
 : @param $count the number of child nodes.
 : @param $begin the input index where the nonterminal begins.
 : @param $end the input index where the nonterminal ends.
 : @return the updated state.
 :)
declare function p:reduce($state as item()+, $name as xs:string, $count as xs:integer, $begin as xs:integer, $end as xs:integer) as item()+
{
  subsequence($state, 1, $count),
  element {$name}
  {
    subsequence($state, $count + 1)
  }
};

(:~
 : Parse start symbol ThymeLeaf from given string.
 :
 : @param $s the string to be parsed.
 : @return the result as generated by parser actions.
 :)
declare function p:parse-ThymeLeaf($s as xs:string) as item()*
{
  let $state := (0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, false())
  let $state := p:parse-ThymeLeaf($s, $state)
  let $error := $state[$p:error]
  return
    if ($error) then
      element ERROR {$error/@*, p:error-message($s, $error)}
    else
      subsequence($state, $p:result)
};

(: End :)
