// Generated by ReScript, PLEASE EDIT WITH CARE

import * as List from "rescript/lib/es6/list.js";
import * as Curry from "rescript/lib/es6/curry.js";
import * as $$Buffer from "rescript/lib/es6/buffer.js";
import * as $$String from "rescript/lib/es6/string.js";
import * as Res_doc from "./res_doc.js";
import * as Caml_obj from "rescript/lib/es6/caml_obj.js";
import * as $$Location from "./location.js";
import * as Res_utf8 from "./res_utf8.js";
import * as Longident from "./longident.js";
import * as Res_token from "./res_token.js";
import * as Ast_helper from "./ast_helper.js";
import * as Pervasives from "rescript/lib/es6/pervasives.js";
import * as Res_js_ffi from "./res_js_ffi.js";
import * as Res_parser from "./res_parser.js";
import * as Caml_option from "rescript/lib/es6/caml_option.js";
import * as Caml_string from "rescript/lib/es6/caml_string.js";
import * as Res_grammar from "./res_grammar.js";
import * as Res_printer from "./res_printer.js";
import * as Res_scanner from "./res_scanner.js";
import * as Res_diagnostics from "./res_diagnostics.js";
import * as Res_comments_table from "./res_comments_table.js";

function mkLoc(startLoc, endLoc) {
  return {
          loc_start: startLoc,
          loc_end: endLoc,
          loc_ghost: false
        };
}

function defaultExpr(param) {
  var id = $$Location.mknoloc("rescript.exprhole");
  return Ast_helper.Exp.mk(undefined, undefined, {
              TAG: /* Pexp_extension */34,
              _0: [
                id,
                {
                  TAG: /* PStr */0,
                  _0: /* [] */0
                }
              ]
            });
}

function defaultType(param) {
  var id = $$Location.mknoloc("rescript.typehole");
  return Ast_helper.Typ.extension(undefined, undefined, [
              id,
              {
                TAG: /* PStr */0,
                _0: /* [] */0
              }
            ]);
}

function defaultPattern(param) {
  var id = $$Location.mknoloc("rescript.patternhole");
  return Ast_helper.Pat.extension(undefined, undefined, [
              id,
              {
                TAG: /* PStr */0,
                _0: /* [] */0
              }
            ]);
}

function defaultModuleExpr(param) {
  return Ast_helper.Mod.structure(undefined, undefined, /* [] */0);
}

function defaultModuleType(param) {
  return Ast_helper.Mty.signature(undefined, undefined, /* [] */0);
}

var id = $$Location.mknoloc("rescript.sigitemhole");

var defaultSignatureItem = Ast_helper.Sig.extension(undefined, undefined, [
      id,
      {
        TAG: /* PStr */0,
        _0: /* [] */0
      }
    ]);

function recoverEqualGreater(p) {
  Res_parser.expect(undefined, /* EqualGreater */57, p);
  var match = p.token;
  if (match === 58) {
    return Res_parser.next(undefined, p);
  }
  
}

function shouldAbortListParse(p) {
  var _breadcrumbs = p.breadcrumbs;
  while(true) {
    var breadcrumbs = _breadcrumbs;
    if (!breadcrumbs) {
      return false;
    }
    if (Res_grammar.isPartOfList(breadcrumbs.hd[0], p.token)) {
      return true;
    }
    _breadcrumbs = breadcrumbs.tl;
    continue ;
  };
}

var Recover = {
  defaultExpr: defaultExpr,
  defaultType: defaultType,
  defaultPattern: defaultPattern,
  defaultModuleExpr: defaultModuleExpr,
  defaultModuleType: defaultModuleType,
  defaultSignatureItem: defaultSignatureItem,
  recoverEqualGreater: recoverEqualGreater,
  shouldAbortListParse: shouldAbortListParse
};

var listPatternSpread = "List pattern matches only supports one `...` spread, at the end.\nExplanation: a list spread at the tail is efficient, but a spread in the middle would create new list[s]; out of performance concern, our pattern matching currently guarantees to never create new intermediate data.";

var recordPatternSpread = "Record's `...` spread is not supported in pattern matches.\nExplanation: you can't collect a subset of a record's field into its own record, since a record needs an explicit declaration and that subset wouldn't have one.\nSolution: you need to pull out each field you want explicitly.";

var arrayPatternSpread = "Array's `...` spread is not supported in pattern matches.\nExplanation: such spread would create a subarray; out of performance concern, our pattern matching currently guarantees to never create new intermediate data.\nSolution: if it's to validate the first few elements, use a `when` clause + Array size check + `get` checks on the current pattern. If it's to obtain a subarray, use `Array.sub` or `Belt.Array.slice`.";

var arrayExprSpread = "Arrays can't use the `...` spread currently. Please use `concat` or other Array helpers.";

var recordExprSpread = "Records can only have one `...` spread, at the beginning.\nExplanation: since records have a known, fixed shape, a spread like `{a, ...b}` wouldn't make sense, as `b` would override every field of `a` anyway.";

var listExprSpread = "Lists can only have one `...` spread, and at the end.\nExplanation: lists are singly-linked list, where a node contains a value and points to the next node. `list[a, ...bc]` efficiently creates a new item and links `bc` as its next nodes. `[...bc, a]` would be expensive, as it'd need to traverse `bc` and prepend each item to `a` one by one. We therefore disallow such syntax sugar.\nSolution: directly use `concat`.";

var variantIdent = "A polymorphic variant (e.g. #id) must start with an alphabetical letter or be a number (e.g. #742)";

function experimentalIfLet(expr) {
  var switchExpr_pexp_desc = expr.pexp_desc;
  var switchExpr_pexp_loc = expr.pexp_loc;
  var switchExpr = {
    pexp_desc: switchExpr_pexp_desc,
    pexp_loc: switchExpr_pexp_loc,
    pexp_attributes: /* [] */0
  };
  return Res_doc.toString(80, Res_doc.concat({
                  hd: Res_doc.text("If-let is currently highly experimental."),
                  tl: {
                    hd: Res_doc.line,
                    tl: {
                      hd: Res_doc.text("Use a regular `switch` with pattern matching instead:"),
                      tl: {
                        hd: Res_doc.concat({
                              hd: Res_doc.hardLine,
                              tl: {
                                hd: Res_doc.hardLine,
                                tl: {
                                  hd: Res_printer.printExpression(switchExpr, Res_comments_table.empty),
                                  tl: /* [] */0
                                }
                              }
                            }),
                        tl: /* [] */0
                      }
                    }
                  }
                }));
}

var typeParam = "A type param consists of a singlequote followed by a name like `'a` or `'A`";

var typeVar = "A type variable consists of a singlequote followed by a name like `'a` or `'A`";

function attributeWithoutNode(attr) {
  var attrName = attr[0].txt;
  return "Did you forget to attach `" + (attrName + ("` to an item?\n  Standalone attributes start with `@@` like: `@@" + (attrName + "`")));
}

function typeDeclarationNameLongident(longident) {
  return "A type declaration's name cannot contain a module access. Did you mean `" + (Longident.last(longident) + "`?");
}

var tupleSingleElement = "A tuple needs at least two elements";

function missingTildeLabeledParameter(name) {
  if (name === "") {
    return "A labeled parameter starts with a `~`.";
  } else {
    return "A labeled parameter starts with a `~`. Did you mean: `~" + (name + "`?");
  }
}

var stringInterpolationInPattern = "String interpolation is not supported in pattern matching.";

var spreadInRecordDeclaration = "A record type declaration doesn't support the ... spread. Only an object (with quoted field names) does.";

function objectQuotedFieldName(name) {
  return "An object type declaration needs quoted field names. Did you mean \"" + (name + "\"?");
}

var forbiddenInlineRecordDeclaration = "An inline record type declaration is only allowed in a variant constructor's declaration";

var sameTypeSpread = "You're using a ... spread without extra fields. This is the same type.";

function polyVarIntWithSuffix(number) {
  return "A numeric polymorphic variant cannot be followed by a letter. Did you mean `#" + (number + "`?");
}

var ErrorMessages = {
  listPatternSpread: listPatternSpread,
  recordPatternSpread: recordPatternSpread,
  arrayPatternSpread: arrayPatternSpread,
  arrayExprSpread: arrayExprSpread,
  recordExprSpread: recordExprSpread,
  listExprSpread: listExprSpread,
  variantIdent: variantIdent,
  experimentalIfLet: experimentalIfLet,
  typeParam: typeParam,
  typeVar: typeVar,
  attributeWithoutNode: attributeWithoutNode,
  typeDeclarationNameLongident: typeDeclarationNameLongident,
  tupleSingleElement: tupleSingleElement,
  missingTildeLabeledParameter: missingTildeLabeledParameter,
  stringInterpolationInPattern: stringInterpolationInPattern,
  spreadInRecordDeclaration: spreadInRecordDeclaration,
  objectQuotedFieldName: objectQuotedFieldName,
  forbiddenInlineRecordDeclaration: forbiddenInlineRecordDeclaration,
  sameTypeSpread: sameTypeSpread,
  polyVarIntWithSuffix: polyVarIntWithSuffix
};

var jsxAttr_0 = $$Location.mknoloc("JSX");

var jsxAttr_1 = {
  TAG: /* PStr */0,
  _0: /* [] */0
};

var jsxAttr = [
  jsxAttr_0,
  jsxAttr_1
];

var uncurryAttr_0 = $$Location.mknoloc("bs");

var uncurryAttr_1 = {
  TAG: /* PStr */0,
  _0: /* [] */0
};

var uncurryAttr = [
  uncurryAttr_0,
  uncurryAttr_1
];

var ternaryAttr_0 = $$Location.mknoloc("ns.ternary");

var ternaryAttr_1 = {
  TAG: /* PStr */0,
  _0: /* [] */0
};

var ternaryAttr = [
  ternaryAttr_0,
  ternaryAttr_1
];

var ifLetAttr_0 = $$Location.mknoloc("ns.iflet");

var ifLetAttr_1 = {
  TAG: /* PStr */0,
  _0: /* [] */0
};

var ifLetAttr = [
  ifLetAttr_0,
  ifLetAttr_1
];

var suppressFragileMatchWarningAttr_0 = $$Location.mknoloc("warning");

var suppressFragileMatchWarningAttr_1 = {
  TAG: /* PStr */0,
  _0: {
    hd: Ast_helper.Str.$$eval(undefined, undefined, Ast_helper.Exp.constant(undefined, undefined, {
              TAG: /* Pconst_string */2,
              _0: "-4",
              _1: undefined
            })),
    tl: /* [] */0
  }
};

var suppressFragileMatchWarningAttr = [
  suppressFragileMatchWarningAttr_0,
  suppressFragileMatchWarningAttr_1
];

function makeBracesAttr(loc) {
  return [
          $$Location.mkloc("ns.braces", loc),
          {
            TAG: /* PStr */0,
            _0: /* [] */0
          }
        ];
}

var templateLiteralAttr_0 = $$Location.mknoloc("res.template");

var templateLiteralAttr_1 = {
  TAG: /* PStr */0,
  _0: /* [] */0
};

var templateLiteralAttr = [
  templateLiteralAttr_0,
  templateLiteralAttr_1
];

function getClosingToken(x) {
  if (typeof x === "number") {
    if (x === 42) {
      return /* GreaterThan */41;
    }
    if (x >= 23) {
      if (x === 79) {
        return /* Rbrace */23;
      }
      
    } else if (x >= 18) {
      switch (x) {
        case /* Lparen */18 :
            return /* Rparen */19;
        case /* Lbracket */20 :
            return /* Rbracket */21;
        case /* Rparen */19 :
        case /* Rbracket */21 :
            break;
        case /* Lbrace */22 :
            return /* Rbrace */23;
        
      }
    }
    
  }
  throw {
        RE_EXN_ID: "Assert_failure",
        _1: [
          "res_core.res",
          207,
          9
        ],
        Error: new Error()
      };
}

function goToClosing(closingToken, state) {
  while(true) {
    var match = state.token;
    var exit = 0;
    if (typeof match === "number") {
      if (match >= 43) {
        exit = match !== 79 ? 1 : 2;
      } else if (match >= 18) {
        switch (match) {
          case /* Rparen */19 :
              if (closingToken === 19) {
                Res_parser.next(undefined, state);
                return ;
              } else {
                return ;
              }
          case /* Rbracket */21 :
              if (closingToken === 21) {
                Res_parser.next(undefined, state);
                return ;
              } else {
                return ;
              }
          case /* Rbrace */23 :
              if (closingToken === 23) {
                Res_parser.next(undefined, state);
                return ;
              } else {
                return ;
              }
          case /* Eof */26 :
              return ;
          case /* Colon */24 :
          case /* Comma */25 :
          case /* Exception */27 :
          case /* Backslash */28 :
          case /* Forwardslash */29 :
          case /* ForwardslashDot */30 :
          case /* Asterisk */31 :
          case /* AsteriskDot */32 :
          case /* Exponentiation */33 :
          case /* Minus */34 :
          case /* MinusDot */35 :
          case /* Plus */36 :
          case /* PlusDot */37 :
          case /* PlusPlus */38 :
          case /* PlusEqual */39 :
          case /* ColonGreaterThan */40 :
              exit = 1;
              break;
          case /* GreaterThan */41 :
              if (closingToken === 41) {
                Res_parser.next(undefined, state);
                return ;
              }
              exit = 1;
              break;
          case /* Lparen */18 :
          case /* Lbracket */20 :
          case /* Lbrace */22 :
          case /* LessThan */42 :
              exit = 2;
              break;
          
        }
      } else {
        exit = 1;
      }
    } else {
      exit = 1;
    }
    switch (exit) {
      case 1 :
          Res_parser.next(undefined, state);
          continue ;
      case 2 :
          Res_parser.next(undefined, state);
          goToClosing(getClosingToken(match), state);
          continue ;
      
    }
  };
}

function isEs6ArrowExpression(inTernary, p) {
  return Res_parser.lookahead(p, (function (state) {
                var match = state.token;
                if (typeof match === "number") {
                  switch (match) {
                    case /* Underscore */12 :
                        break;
                    case /* Lparen */18 :
                        var prevEndPos = state.prevEndPos;
                        Res_parser.next(undefined, state);
                        var match$1 = state.token;
                        var exit = 0;
                        if (typeof match$1 === "number") {
                          if (match$1 >= 20) {
                            if (match$1 === 48) {
                              return true;
                            }
                            if (match$1 === 80) {
                              return false;
                            }
                            exit = 2;
                          } else {
                            if (match$1 === 4) {
                              return true;
                            }
                            if (match$1 >= 19) {
                              Res_parser.next(undefined, state);
                              var match$2 = state.token;
                              if (typeof match$2 !== "number") {
                                return false;
                              }
                              if (match$2 !== 24) {
                                return match$2 === 57;
                              }
                              if (inTernary) {
                                return false;
                              }
                              Res_parser.next(undefined, state);
                              var match$3 = state.token;
                              if (typeof match$3 === "number") {
                                return true;
                              }
                              if (match$3.TAG !== /* Lident */4) {
                                return true;
                              }
                              Res_parser.next(undefined, state);
                              var match$4 = state.token;
                              if (match$4 === 42) {
                                Res_parser.next(undefined, state);
                                goToClosing(/* GreaterThan */41, state);
                              }
                              var match$5 = state.token;
                              return match$5 === 57;
                            } else {
                              exit = 2;
                            }
                          }
                        } else {
                          exit = 2;
                        }
                        if (exit === 2) {
                          goToClosing(/* Rparen */19, state);
                          var match$6 = state.token;
                          var exit$1 = 0;
                          if (typeof match$6 === "number") {
                            if (match$6 === 19) {
                              return false;
                            }
                            if (match$6 !== 24) {
                              if (match$6 === 57) {
                                return true;
                              }
                              exit$1 = 3;
                            } else {
                              if (!inTernary) {
                                return true;
                              }
                              exit$1 = 3;
                            }
                          } else {
                            exit$1 = 3;
                          }
                          if (exit$1 === 3) {
                            Res_parser.nextUnsafe(state);
                            var match$7 = state.token;
                            if (match$7 === 57) {
                              return state.startPos.pos_lnum === prevEndPos.pos_lnum;
                            } else {
                              return false;
                            }
                          }
                          
                        }
                        break;
                    default:
                      return false;
                  }
                } else if (match.TAG !== /* Lident */4) {
                  return false;
                }
                Res_parser.next(undefined, state);
                var match$8 = state.token;
                return match$8 === 57;
              }));
}

function isEs6ArrowFunctor(p) {
  return Res_parser.lookahead(p, (function (state) {
                var match = state.token;
                if (match !== 18) {
                  return false;
                }
                Res_parser.next(undefined, state);
                var match$1 = state.token;
                if (match$1 === 19) {
                  Res_parser.next(undefined, state);
                  var match$2 = state.token;
                  if (typeof match$2 === "number") {
                    if (match$2 !== 24) {
                      return match$2 === 57;
                    } else {
                      return true;
                    }
                  } else {
                    return false;
                  }
                }
                goToClosing(/* Rparen */19, state);
                var match$3 = state.token;
                if (typeof match$3 !== "number") {
                  return false;
                }
                if (match$3 >= 25) {
                  return match$3 === 57;
                }
                if (match$3 < 22) {
                  return false;
                }
                switch (match$3) {
                  case /* Rbrace */23 :
                      return false;
                  case /* Lbrace */22 :
                  case /* Colon */24 :
                      return true;
                  
                }
              }));
}

function isEs6ArrowType(p) {
  return Res_parser.lookahead(p, (function (state) {
                var match = state.token;
                if (typeof match !== "number") {
                  return false;
                }
                if (match !== 18) {
                  return match === 48;
                }
                Res_parser.next(undefined, state);
                var match$1 = state.token;
                if (typeof match$1 === "number") {
                  if (match$1 > 47 || match$1 < 5) {
                    if (!(match$1 > 48 || match$1 < 4)) {
                      return true;
                    }
                    
                  } else if (match$1 === 19) {
                    Res_parser.next(undefined, state);
                    var match$2 = state.token;
                    return match$2 === 57;
                  }
                  
                }
                goToClosing(/* Rparen */19, state);
                var match$3 = state.token;
                return match$3 === 57;
              }));
}

function buildLongident(words) {
  var match = List.rev(words);
  if (match) {
    return List.fold_left((function (p, s) {
                  return {
                          TAG: /* Ldot */1,
                          _0: p,
                          _1: s
                        };
                }), {
                TAG: /* Lident */0,
                _0: match.hd
              }, match.tl);
  }
  throw {
        RE_EXN_ID: "Assert_failure",
        _1: [
          "res_core.res",
          363,
          14
        ],
        Error: new Error()
      };
}

function makeInfixOperator(p, token, startPos, endPos) {
  var stringifiedToken = token === /* MinusGreater */58 ? "|." : (
      token === /* PlusPlus */38 ? "^" : (
          token === /* BangEqual */70 ? "<>" : (
              token === /* BangEqualEqual */71 ? "!=" : (
                  token === /* Equal */14 ? (Res_parser.err(startPos, endPos, p, Res_diagnostics.message("Did you mean `==` here?")), "=") : (
                      token === /* EqualEqual */15 ? "=" : (
                          token === /* EqualEqualEqual */16 ? "==" : Res_token.toString(token)
                        )
                    )
                )
            )
        )
    );
  var loc = {
    loc_start: startPos,
    loc_end: endPos,
    loc_ghost: false
  };
  var operator = $$Location.mkloc({
        TAG: /* Lident */0,
        _0: stringifiedToken
      }, loc);
  return Ast_helper.Exp.ident(loc, undefined, operator);
}

function negateString(s) {
  if (s.length !== 0 && Caml_string.get(s, 0) === /* '-' */45) {
    return $$String.sub(s, 1, s.length - 1 | 0);
  } else {
    return "-" + s;
  }
}

function makeUnaryExpr(startPos, tokenEnd, token, operand) {
  var match = operand.pexp_desc;
  var exit = 0;
  if (typeof token === "number") {
    if (token >= 34) {
      if (token >= 36) {
        if (token < 38 && typeof match !== "number" && match.TAG === /* Pexp_constant */1) {
          switch (match._0.TAG | 0) {
            case /* Pconst_char */1 :
            case /* Pconst_string */2 :
                break;
            case /* Pconst_integer */0 :
            case /* Pconst_float */3 :
                return operand;
            
          }
        }
        
      } else if (token >= 35 || typeof match === "number" || match.TAG !== /* Pexp_constant */1) {
        exit = 2;
      } else {
        var match$1 = match._0;
        if (match$1.TAG === /* Pconst_integer */0) {
          return {
                  pexp_desc: {
                    TAG: /* Pexp_constant */1,
                    _0: {
                      TAG: /* Pconst_integer */0,
                      _0: negateString(match$1._0),
                      _1: match$1._1
                    }
                  },
                  pexp_loc: operand.pexp_loc,
                  pexp_attributes: operand.pexp_attributes
                };
        }
        exit = 2;
      }
    } else if (token === 7) {
      var tokenLoc = {
        loc_start: startPos,
        loc_end: tokenEnd,
        loc_ghost: false
      };
      return Ast_helper.Exp.apply({
                  loc_start: startPos,
                  loc_end: operand.pexp_loc.loc_end,
                  loc_ghost: false
                }, undefined, Ast_helper.Exp.ident(tokenLoc, undefined, $$Location.mkloc({
                          TAG: /* Lident */0,
                          _0: "not"
                        }, tokenLoc)), {
                  hd: [
                    /* Nolabel */0,
                    operand
                  ],
                  tl: /* [] */0
                });
    }
    
  }
  if (exit === 2 && typeof match !== "number" && match.TAG === /* Pexp_constant */1) {
    var match$2 = match._0;
    if (match$2.TAG === /* Pconst_float */3) {
      return {
              pexp_desc: {
                TAG: /* Pexp_constant */1,
                _0: {
                  TAG: /* Pconst_float */3,
                  _0: negateString(match$2._0),
                  _1: match$2._1
                }
              },
              pexp_loc: operand.pexp_loc,
              pexp_attributes: operand.pexp_attributes
            };
    }
    
  }
  if (typeof token !== "number") {
    return operand;
  }
  if (token > 37 || token < 34) {
    return operand;
  }
  var tokenLoc$1 = {
    loc_start: startPos,
    loc_end: tokenEnd,
    loc_ghost: false
  };
  var operator = "~" + Res_token.toString(token);
  return Ast_helper.Exp.apply({
              loc_start: startPos,
              loc_end: operand.pexp_loc.loc_end,
              loc_ghost: false
            }, undefined, Ast_helper.Exp.ident(tokenLoc$1, undefined, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: operator
                    }, tokenLoc$1)), {
              hd: [
                /* Nolabel */0,
                operand
              ],
              tl: /* [] */0
            });
}

function makeListExpression(loc, seq, extOpt) {
  var handleSeq = function (x) {
    if (x) {
      var e1 = x.hd;
      var exp_el = handleSeq(x.tl);
      var loc_loc_start = e1.pexp_loc.loc_start;
      var loc_loc_end = exp_el.pexp_loc.loc_end;
      var loc$1 = {
        loc_start: loc_loc_start,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      var arg = Ast_helper.Exp.tuple(loc$1, undefined, {
            hd: e1,
            tl: {
              hd: exp_el,
              tl: /* [] */0
            }
          });
      return Ast_helper.Exp.construct(loc$1, undefined, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: "::"
                    }, loc$1), arg);
    }
    if (extOpt !== undefined) {
      return extOpt;
    }
    var loc_loc_start$1 = loc.loc_start;
    var loc_loc_end$1 = loc.loc_end;
    var loc$2 = {
      loc_start: loc_loc_start$1,
      loc_end: loc_loc_end$1,
      loc_ghost: true
    };
    var nil = $$Location.mkloc({
          TAG: /* Lident */0,
          _0: "[]"
        }, loc$2);
    return Ast_helper.Exp.construct(loc$2, undefined, nil, undefined);
  };
  var expr = handleSeq(seq);
  return {
          pexp_desc: expr.pexp_desc,
          pexp_loc: loc,
          pexp_attributes: expr.pexp_attributes
        };
}

function makeListPattern(loc, seq, ext_opt) {
  var handle_seq = function (x) {
    if (x) {
      var p1 = x.hd;
      var pat_pl = handle_seq(x.tl);
      var loc_loc_start = p1.ppat_loc.loc_start;
      var loc_loc_end = pat_pl.ppat_loc.loc_end;
      var loc$1 = {
        loc_start: loc_loc_start,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      var arg = Ast_helper.Pat.mk(loc$1, undefined, {
            TAG: /* Ppat_tuple */4,
            _0: {
              hd: p1,
              tl: {
                hd: pat_pl,
                tl: /* [] */0
              }
            }
          });
      return Ast_helper.Pat.mk(loc$1, undefined, {
                  TAG: /* Ppat_construct */5,
                  _0: $$Location.mkloc({
                        TAG: /* Lident */0,
                        _0: "::"
                      }, loc$1),
                  _1: arg
                });
    }
    if (ext_opt !== undefined) {
      return ext_opt;
    }
    var loc_loc_start$1 = loc.loc_start;
    var loc_loc_end$1 = loc.loc_end;
    var loc$2 = {
      loc_start: loc_loc_start$1,
      loc_end: loc_loc_end$1,
      loc_ghost: true
    };
    var nil_txt = {
      TAG: /* Lident */0,
      _0: "[]"
    };
    var nil = {
      txt: nil_txt,
      loc: loc$2
    };
    return Ast_helper.Pat.construct(loc$2, undefined, nil, undefined);
  };
  return handle_seq(seq);
}

function lidentOfPath(longident) {
  var match = List.rev(Longident.flatten(longident));
  if (match) {
    return match.hd;
  } else {
    return "";
  }
}

function makeNewtypes(attrs, loc, newtypes, exp) {
  var expr = List.fold_right((function (newtype, exp) {
          return Ast_helper.Exp.mk(loc, undefined, {
                      TAG: /* Pexp_newtype */31,
                      _0: newtype,
                      _1: exp
                    });
        }), newtypes, exp);
  return {
          pexp_desc: expr.pexp_desc,
          pexp_loc: expr.pexp_loc,
          pexp_attributes: attrs
        };
}

function wrapTypeAnnotation(loc, newtypes, core_type, body) {
  var exp = makeNewtypes(/* [] */0, loc, newtypes, Ast_helper.Exp.constraint_(loc, undefined, body, core_type));
  var typ = Ast_helper.Typ.poly(loc, undefined, newtypes, Ast_helper.Typ.varify_constructors(newtypes, core_type));
  return [
          exp,
          typ
        ];
}

function processUnderscoreApplication(args) {
  var exp_question = {
    contents: undefined
  };
  var hidden_var = "__x";
  var check_arg = function (arg) {
    var exp = arg[1];
    var id = exp.pexp_desc;
    if (typeof id === "number") {
      return arg;
    }
    if (id.TAG !== /* Pexp_ident */0) {
      return arg;
    }
    var id$1 = id._0;
    var match = id$1.txt;
    switch (match.TAG | 0) {
      case /* Lident */0 :
          if (match._0 !== "_") {
            return arg;
          }
          var new_id = $$Location.mkloc({
                TAG: /* Lident */0,
                _0: hidden_var
              }, id$1.loc);
          var new_exp = Ast_helper.Exp.mk(exp.pexp_loc, undefined, {
                TAG: /* Pexp_ident */0,
                _0: new_id
              });
          exp_question.contents = new_exp;
          return [
                  arg[0],
                  new_exp
                ];
      case /* Ldot */1 :
      case /* Lapply */2 :
          return arg;
      
    }
  };
  var args$1 = List.map(check_arg, args);
  var wrap = function (exp_apply) {
    var match = exp_question.contents;
    if (match === undefined) {
      return exp_apply;
    }
    var loc = match.pexp_loc;
    var pattern = Ast_helper.Pat.mk(loc, undefined, {
          TAG: /* Ppat_var */0,
          _0: $$Location.mkloc(hidden_var, loc)
        });
    return Ast_helper.Exp.mk(loc, undefined, {
                TAG: /* Pexp_fun */4,
                _0: /* Nolabel */0,
                _1: undefined,
                _2: pattern,
                _3: exp_apply
              });
  };
  return [
          args$1,
          wrap
        ];
}

function hexValue(ch) {
  if (ch >= 65) {
    if (ch >= 97) {
      if (ch >= 103) {
        return 16;
      } else {
        return (ch - /* 'a' */97 | 0) + 10 | 0;
      }
    } else if (ch >= 71) {
      return 16;
    } else {
      return ((ch + 32 | 0) - /* 'a' */97 | 0) + 10 | 0;
    }
  } else if (ch > 57 || ch < 48) {
    return 16;
  } else {
    return ch - 48 | 0;
  }
}

function removeModuleNameFromPunnedFieldValue(exp) {
  var pathIdent = exp.pexp_desc;
  if (typeof pathIdent === "number") {
    return exp;
  }
  if (pathIdent.TAG !== /* Pexp_ident */0) {
    return exp;
  }
  var pathIdent$1 = pathIdent._0;
  return {
          pexp_desc: {
            TAG: /* Pexp_ident */0,
            _0: {
              txt: {
                TAG: /* Lident */0,
                _0: Longident.last(pathIdent$1.txt)
              },
              loc: pathIdent$1.loc
            }
          },
          pexp_loc: exp.pexp_loc,
          pexp_attributes: exp.pexp_attributes
        };
}

function parseStringLiteral(s) {
  var len = s.length;
  var b = $$Buffer.create(s.length);
  var parse = function (_state, _i, _d) {
    while(true) {
      var d = _d;
      var i = _i;
      var state = _state;
      if (i === len) {
        return state > 6 || state < 2;
      }
      var c = s.charCodeAt(i);
      switch (state) {
        case /* Start */0 :
            if (c !== 92) {
              $$Buffer.add_char(b, c);
              _i = i + 1 | 0;
              _state = /* Start */0;
              continue ;
            }
            _i = i + 1 | 0;
            _state = /* Backslash */1;
            continue ;
        case /* Backslash */1 :
            var exit = 0;
            if (c >= 32) {
              if (c < 58) {
                if (c >= 40) {
                  if (c >= 48) {
                    _d = 0;
                    _state = /* DecimalEscape */3;
                    continue ;
                  }
                  exit = 1;
                } else {
                  switch (c) {
                    case 33 :
                    case 35 :
                    case 36 :
                    case 37 :
                    case 38 :
                        exit = 1;
                        break;
                    case 32 :
                    case 34 :
                    case 39 :
                        exit = 2;
                        break;
                    
                  }
                }
              } else {
                switch (c) {
                  case 92 :
                      exit = 2;
                      break;
                  case 98 :
                      $$Buffer.add_char(b, /* '\b' */8);
                      _i = i + 1 | 0;
                      _state = /* Start */0;
                      continue ;
                  case 110 :
                      $$Buffer.add_char(b, /* '\n' */10);
                      _i = i + 1 | 0;
                      _state = /* Start */0;
                      continue ;
                  case 111 :
                      _d = 0;
                      _i = i + 1 | 0;
                      _state = /* OctalEscape */4;
                      continue ;
                  case 114 :
                      $$Buffer.add_char(b, /* '\r' */13);
                      _i = i + 1 | 0;
                      _state = /* Start */0;
                      continue ;
                  case 116 :
                      $$Buffer.add_char(b, /* '\t' */9);
                      _i = i + 1 | 0;
                      _state = /* Start */0;
                      continue ;
                  case 117 :
                      _d = 0;
                      _i = i + 1 | 0;
                      _state = /* UnicodeEscapeStart */7;
                      continue ;
                  case 93 :
                  case 94 :
                  case 95 :
                  case 96 :
                  case 97 :
                  case 99 :
                  case 100 :
                  case 101 :
                  case 102 :
                  case 103 :
                  case 104 :
                  case 105 :
                  case 106 :
                  case 107 :
                  case 108 :
                  case 109 :
                  case 112 :
                  case 113 :
                  case 115 :
                  case 118 :
                  case 119 :
                      exit = 1;
                      break;
                  case 120 :
                      _d = 0;
                      _i = i + 1 | 0;
                      _state = /* HexEscape */2;
                      continue ;
                  default:
                    exit = 1;
                }
              }
            } else if (c !== 10) {
              if (c !== 13) {
                exit = 1;
              } else {
                _i = i + 1 | 0;
                _state = /* EscapedLineBreak */8;
                continue ;
              }
            } else {
              _i = i + 1 | 0;
              _state = /* EscapedLineBreak */8;
              continue ;
            }
            switch (exit) {
              case 1 :
                  $$Buffer.add_char(b, /* '\\' */92);
                  $$Buffer.add_char(b, c);
                  _i = i + 1 | 0;
                  _state = /* Start */0;
                  continue ;
              case 2 :
                  $$Buffer.add_char(b, c);
                  _i = i + 1 | 0;
                  _state = /* Start */0;
                  continue ;
              
            }
            break;
        case /* HexEscape */2 :
            if (d === 1) {
              var c0 = s.charCodeAt(i - 1 | 0);
              var c1 = s.charCodeAt(i);
              var c$1 = (hexValue(c0) << 4) + hexValue(c1) | 0;
              if (c$1 < 0 || c$1 > 255) {
                return false;
              }
              $$Buffer.add_char(b, c$1);
              _d = 0;
              _i = i + 1 | 0;
              _state = /* Start */0;
              continue ;
            }
            _d = d + 1 | 0;
            _i = i + 1 | 0;
            _state = /* HexEscape */2;
            continue ;
        case /* DecimalEscape */3 :
            if (d === 2) {
              var c0$1 = s.charCodeAt(i - 2 | 0);
              var c1$1 = s.charCodeAt(i - 1 | 0);
              var c2 = s.charCodeAt(i);
              var c$2 = (Math.imul(100, c0$1 - 48 | 0) + Math.imul(10, c1$1 - 48 | 0) | 0) + (c2 - 48 | 0) | 0;
              if (c$2 < 0 || c$2 > 255) {
                return false;
              }
              $$Buffer.add_char(b, c$2);
              _d = 0;
              _i = i + 1 | 0;
              _state = /* Start */0;
              continue ;
            }
            _d = d + 1 | 0;
            _i = i + 1 | 0;
            _state = /* DecimalEscape */3;
            continue ;
        case /* OctalEscape */4 :
            if (d === 2) {
              var c0$2 = s.charCodeAt(i - 2 | 0);
              var c1$2 = s.charCodeAt(i - 1 | 0);
              var c2$1 = s.charCodeAt(i);
              var c$3 = (((c0$2 - 48 | 0) << 6) + ((c1$2 - 48 | 0) << 3) | 0) + (c2$1 - 48 | 0) | 0;
              if (c$3 < 0 || c$3 > 255) {
                return false;
              }
              $$Buffer.add_char(b, c$3);
              _d = 0;
              _i = i + 1 | 0;
              _state = /* Start */0;
              continue ;
            }
            _d = d + 1 | 0;
            _i = i + 1 | 0;
            _state = /* OctalEscape */4;
            continue ;
        case /* UnicodeEscape */5 :
            if (d === 3) {
              var c0$3 = s.charCodeAt(i - 3 | 0);
              var c1$3 = s.charCodeAt(i - 2 | 0);
              var c2$2 = s.charCodeAt(i - 1 | 0);
              var c3 = s.charCodeAt(i);
              var c$4 = (((hexValue(c0$3) << 12) + (hexValue(c1$3) << 8) | 0) + (hexValue(c2$2) << 4) | 0) + hexValue(c3) | 0;
              if (!Res_utf8.isValidCodePoint(c$4)) {
                return false;
              }
              var codePoint = Res_utf8.encodeCodePoint(c$4);
              $$Buffer.add_string(b, codePoint);
              _d = 0;
              _i = i + 1 | 0;
              _state = /* Start */0;
              continue ;
            }
            _d = d + 1 | 0;
            _i = i + 1 | 0;
            _state = /* UnicodeEscape */5;
            continue ;
        case /* UnicodeCodePointEscape */6 :
            if (c >= 71) {
              if (c >= 103) {
                if (c !== 125) {
                  return false;
                }
                var x = 0;
                for(var remaining = d; remaining >= 1; --remaining){
                  var ix = i - remaining | 0;
                  x = (x << 4) + hexValue(s.charCodeAt(ix)) | 0;
                }
                var c$5 = x;
                if (!Res_utf8.isValidCodePoint(c$5)) {
                  return false;
                }
                var codePoint$1 = Res_utf8.encodeCodePoint(x);
                $$Buffer.add_string(b, codePoint$1);
                _d = 0;
                _i = i + 1 | 0;
                _state = /* Start */0;
                continue ;
              }
              if (c < 97) {
                return false;
              }
              
            } else if (c >= 58) {
              if (c < 65) {
                return false;
              }
              
            } else if (c < 48) {
              return false;
            }
            _d = d + 1 | 0;
            _i = i + 1 | 0;
            _state = /* UnicodeCodePointEscape */6;
            continue ;
        case /* UnicodeEscapeStart */7 :
            if (c !== 123) {
              _d = 1;
              _i = i + 1 | 0;
              _state = /* UnicodeEscape */5;
              continue ;
            }
            _d = 0;
            _i = i + 1 | 0;
            _state = /* UnicodeCodePointEscape */6;
            continue ;
        case /* EscapedLineBreak */8 :
            if (c !== 9) {
              if (c !== 32) {
                $$Buffer.add_char(b, c);
                _i = i + 1 | 0;
                _state = /* Start */0;
                continue ;
              }
              _i = i + 1 | 0;
              _state = /* EscapedLineBreak */8;
              continue ;
            }
            _i = i + 1 | 0;
            _state = /* EscapedLineBreak */8;
            continue ;
        
      }
    };
  };
  if (parse(/* Start */0, 0, 0)) {
    return $$Buffer.contents(b);
  } else {
    return s;
  }
}

function parseLident(p) {
  while(true) {
    var recoverLident = function (p) {
      if (Res_token.isKeyword(p.token) && p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
        Res_parser.err(undefined, undefined, p, Res_diagnostics.lident(p.token));
        Res_parser.next(undefined, p);
        return ;
      }
      var loop = function (p) {
        while(true) {
          if (shouldAbortListParse(p)) {
            return ;
          }
          Res_parser.next(undefined, p);
          continue ;
        };
      };
      Res_parser.err(undefined, undefined, p, Res_diagnostics.lident(p.token));
      Res_parser.next(undefined, p);
      loop(p);
      var match = p.token;
      if (typeof match === "number" || match.TAG !== /* Lident */4) {
        return ;
      } else {
        return Caml_option.some(undefined);
      }
    };
    var startPos = p.startPos;
    var ident = p.token;
    if (typeof ident !== "number" && ident.TAG === /* Lident */4) {
      Res_parser.next(undefined, p);
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: startPos,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      return [
              ident._0,
              loc
            ];
    }
    var match = recoverLident(p);
    if (match === undefined) {
      return [
              "_",
              {
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              }
            ];
    }
    continue ;
  };
}

function parseIdent(msg, startPos, p) {
  var token = p.token;
  var exit = 0;
  if (typeof token === "number") {
    exit = 2;
  } else {
    switch (token.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 1;
          break;
      default:
        exit = 2;
    }
  }
  switch (exit) {
    case 1 :
        Res_parser.next(undefined, p);
        var loc_loc_end = p.prevEndPos;
        var loc = {
          loc_start: startPos,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        return [
                token._0,
                loc
              ];
    case 2 :
        if (Res_token.isKeyword(token) && p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
          var tokenTxt = Res_token.toString(token);
          var msg$1 = "`" + (tokenTxt + ("` is a reserved keyword. Keywords need to be escaped: \\\"" + (tokenTxt + "\"")));
          Res_parser.err(startPos, undefined, p, Res_diagnostics.message(msg$1));
          Res_parser.next(undefined, p);
          return [
                  tokenTxt,
                  {
                    loc_start: startPos,
                    loc_end: p.prevEndPos,
                    loc_ghost: false
                  }
                ];
        }
        Res_parser.err(startPos, undefined, p, Res_diagnostics.message(msg));
        Res_parser.next(undefined, p);
        return [
                "",
                {
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                }
              ];
    
  }
}

function parseHashIdent(startPos, p) {
  Res_parser.expect(undefined, /* Hash */44, p);
  var text = p.token;
  if (typeof text === "number") {
    return parseIdent(variantIdent, startPos, p);
  }
  switch (text.TAG | 0) {
    case /* Int */1 :
        var i = text.i;
        if (text.suffix !== undefined) {
          Res_parser.err(undefined, undefined, p, Res_diagnostics.message(polyVarIntWithSuffix(i)));
        }
        Res_parser.next(undefined, p);
        return [
                i,
                {
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                }
              ];
    case /* String */3 :
        var text$1 = text._0;
        var text$2 = p.mode === /* ParseForTypeChecker */0 ? parseStringLiteral(text$1) : text$1;
        Res_parser.next(undefined, p);
        return [
                text$2,
                {
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                }
              ];
    default:
      return parseIdent(variantIdent, startPos, p);
  }
}

function parseValuePath(p) {
  var startPos = p.startPos;
  var aux = function (p, _path) {
    while(true) {
      var path = _path;
      var ident = p.token;
      if (typeof ident !== "number") {
        switch (ident.TAG | 0) {
          case /* Lident */4 :
              return {
                      TAG: /* Ldot */1,
                      _0: path,
                      _1: ident._0
                    };
          case /* Uident */5 :
              Res_parser.next(undefined, p);
              if (p.token === /* Dot */4) {
                Res_parser.expect(undefined, /* Dot */4, p);
                _path = {
                  TAG: /* Ldot */1,
                  _0: path,
                  _1: ident._0
                };
                continue ;
              }
              Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
              return path;
          default:
            
        }
      }
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident, p.breadcrumbs));
      return {
              TAG: /* Ldot */1,
              _0: path,
              _1: "_"
            };
    };
  };
  var ident = p.token;
  var ident$1;
  var exit = 0;
  if (typeof ident === "number") {
    exit = 1;
  } else {
    switch (ident.TAG | 0) {
      case /* Lident */4 :
          ident$1 = {
            TAG: /* Lident */0,
            _0: ident._0
          };
          break;
      case /* Uident */5 :
          var ident$2 = ident._0;
          Res_parser.next(undefined, p);
          if (p.token === /* Dot */4) {
            Res_parser.expect(undefined, /* Dot */4, p);
            ident$1 = aux(p, {
                  TAG: /* Lident */0,
                  _0: ident$2
                });
          } else {
            Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
            ident$1 = {
              TAG: /* Lident */0,
              _0: ident$2
            };
          }
          break;
      default:
        exit = 1;
    }
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident, p.breadcrumbs));
    ident$1 = {
      TAG: /* Lident */0,
      _0: "_"
    };
  }
  Res_parser.next(undefined, p);
  return $$Location.mkloc(ident$1, {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            });
}

function parseValuePathAfterDot(p) {
  var startPos = p.startPos;
  var token = p.token;
  if (typeof token !== "number") {
    switch (token.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          return parseValuePath(p);
      default:
        
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
  return $$Location.mkloc({
              TAG: /* Lident */0,
              _0: "_"
            }, {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            });
}

function parseValuePathTail(p, startPos, ident) {
  var _path = ident;
  while(true) {
    var path = _path;
    var ident$1 = p.token;
    if (typeof ident$1 !== "number") {
      switch (ident$1.TAG | 0) {
        case /* Lident */4 :
            Res_parser.next(undefined, p);
            return $$Location.mkloc({
                        TAG: /* Ldot */1,
                        _0: path,
                        _1: ident$1._0
                      }, {
                        loc_start: startPos,
                        loc_end: p.prevEndPos,
                        loc_ghost: false
                      });
        case /* Uident */5 :
            Res_parser.next(undefined, p);
            Res_parser.expect(undefined, /* Dot */4, p);
            _path = {
              TAG: /* Ldot */1,
              _0: path,
              _1: ident$1._0
            };
            continue ;
        default:
          
      }
    }
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident$1, p.breadcrumbs));
    return $$Location.mkloc({
                TAG: /* Ldot */1,
                _0: path,
                _1: "_"
              }, {
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              });
  };
}

function parseModuleLongIdentTail(lowercase, p, startPos, ident) {
  var _acc = ident;
  while(true) {
    var acc = _acc;
    var ident$1 = p.token;
    if (typeof ident$1 !== "number") {
      switch (ident$1.TAG | 0) {
        case /* Lident */4 :
            if (lowercase) {
              Res_parser.next(undefined, p);
              var lident_1 = ident$1._0;
              var lident = {
                TAG: /* Ldot */1,
                _0: acc,
                _1: lident_1
              };
              return $$Location.mkloc(lident, {
                          loc_start: startPos,
                          loc_end: p.prevEndPos,
                          loc_ghost: false
                        });
            }
            break;
        case /* Uident */5 :
            Res_parser.next(undefined, p);
            var endPos = p.prevEndPos;
            var lident_1$1 = ident$1._0;
            var lident$1 = {
              TAG: /* Ldot */1,
              _0: acc,
              _1: lident_1$1
            };
            var match = p.token;
            if (match !== 4) {
              return $$Location.mkloc(lident$1, {
                          loc_start: startPos,
                          loc_end: endPos,
                          loc_ghost: false
                        });
            }
            Res_parser.next(undefined, p);
            _acc = lident$1;
            continue ;
        default:
          
      }
    }
    Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident$1));
    return $$Location.mkloc({
                TAG: /* Ldot */1,
                _0: acc,
                _1: "_"
              }, {
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              });
  };
}

function parseModuleLongIdent(lowercase, p) {
  var startPos = p.startPos;
  var ident = p.token;
  if (typeof ident !== "number") {
    switch (ident.TAG | 0) {
      case /* Lident */4 :
          if (lowercase) {
            var loc_loc_end = p.endPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var lident = {
              TAG: /* Lident */0,
              _0: ident._0
            };
            Res_parser.next(undefined, p);
            return $$Location.mkloc(lident, loc);
          }
          break;
      case /* Uident */5 :
          var lident$1 = {
            TAG: /* Lident */0,
            _0: ident._0
          };
          var endPos = p.endPos;
          Res_parser.next(undefined, p);
          var match = p.token;
          if (match === 4) {
            Res_parser.next(undefined, p);
            return parseModuleLongIdentTail(lowercase, p, startPos, lident$1);
          } else {
            return $$Location.mkloc(lident$1, {
                        loc_start: startPos,
                        loc_end: endPos,
                        loc_ghost: false
                      });
          }
      default:
        
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
  return $$Location.mkloc({
              TAG: /* Lident */0,
              _0: "_"
            }, {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            });
}

function parseIdentPath(p) {
  var match = p.token;
  if (typeof match === "number") {
    return {
            TAG: /* Lident */0,
            _0: "_"
          };
  }
  switch (match.TAG | 0) {
    case /* Lident */4 :
    case /* Uident */5 :
        break;
    default:
      return {
              TAG: /* Lident */0,
              _0: "_"
            };
  }
  var ident = match._0;
  Res_parser.next(undefined, p);
  var match$1 = p.token;
  if (match$1 === 4) {
    Res_parser.next(undefined, p);
    var _acc = {
      TAG: /* Lident */0,
      _0: ident
    };
    while(true) {
      var acc = _acc;
      var _t = p.token;
      if (typeof _t === "number") {
        return acc;
      }
      switch (_t.TAG | 0) {
        case /* Lident */4 :
        case /* Uident */5 :
            break;
        default:
          return acc;
      }
      Res_parser.next(undefined, p);
      var lident_1 = _t._0;
      var lident = {
        TAG: /* Ldot */1,
        _0: acc,
        _1: lident_1
      };
      var match$2 = p.token;
      if (match$2 !== 4) {
        return lident;
      }
      Res_parser.next(undefined, p);
      _acc = lident;
      continue ;
    };
  } else {
    return {
            TAG: /* Lident */0,
            _0: ident
          };
  }
}

function verifyJsxOpeningClosingName(p, nameExpr) {
  var lident = p.token;
  var closing;
  if (typeof lident === "number") {
    closing = {
      TAG: /* Lident */0,
      _0: ""
    };
  } else {
    switch (lident.TAG | 0) {
      case /* Lident */4 :
          Res_parser.next(undefined, p);
          closing = {
            TAG: /* Lident */0,
            _0: lident._0
          };
          break;
      case /* Uident */5 :
          closing = parseModuleLongIdent(true, p).txt;
          break;
      default:
        closing = {
          TAG: /* Lident */0,
          _0: ""
        };
    }
  }
  var openingIdent = nameExpr.pexp_desc;
  if (typeof openingIdent === "number") {
    throw {
          RE_EXN_ID: "Assert_failure",
          _1: [
            "res_core.res",
            975,
            9
          ],
          Error: new Error()
        };
  }
  if (openingIdent.TAG === /* Pexp_ident */0) {
    var withoutCreateElement = List.filter(function (s) {
            return s !== "createElement";
          })(Longident.flatten(openingIdent._0.txt));
    var li = Longident.unflatten(withoutCreateElement);
    var opening = li !== undefined ? li : ({
          TAG: /* Lident */0,
          _0: ""
        });
    return Caml_obj.caml_equal(opening, closing);
  }
  throw {
        RE_EXN_ID: "Assert_failure",
        _1: [
          "res_core.res",
          975,
          9
        ],
        Error: new Error()
      };
}

function string_of_pexp_ident(nameExpr) {
  var openingIdent = nameExpr.pexp_desc;
  if (typeof openingIdent === "number" || openingIdent.TAG !== /* Pexp_ident */0) {
    return "";
  } else {
    return $$String.concat(".", List.filter(function (s) {
                      return s !== "createElement";
                    })(Longident.flatten(openingIdent._0.txt)));
  }
}

function parseOpenDescription(attrs, p) {
  Res_parser.leaveBreadcrumb(p, /* OpenDescription */0);
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Open */0, p);
  var override = Res_parser.optional(p, /* Bang */7) ? /* Override */0 : /* Fresh */1;
  var modident = parseModuleLongIdent(false, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  Res_parser.eatBreadcrumb(p);
  return Ast_helper.Opn.mk(loc, attrs, undefined, override, modident);
}

function parseTemplateStringLiteral(s) {
  var len = s.length;
  var b = $$Buffer.create(len);
  var loop = function (_i) {
    while(true) {
      var i = _i;
      if (i >= len) {
        return ;
      }
      var c = s.charCodeAt(i);
      if (c !== 92) {
        $$Buffer.add_char(b, c);
        _i = i + 1 | 0;
        continue ;
      }
      if ((i + 1 | 0) >= len) {
        return $$Buffer.add_char(b, c);
      }
      var nextChar = s.charCodeAt(i + 1 | 0);
      var exit = 0;
      if (nextChar >= 36) {
        exit = nextChar > 95 || nextChar < 37 ? (
            nextChar >= 97 ? 2 : 1
          ) : (
            nextChar !== 92 ? 2 : 1
          );
      } else if (nextChar !== 10) {
        if (nextChar !== 13) {
          exit = 2;
        } else {
          _i = i + 2 | 0;
          continue ;
        }
      } else {
        _i = i + 2 | 0;
        continue ;
      }
      switch (exit) {
        case 1 :
            $$Buffer.add_char(b, nextChar);
            _i = i + 2 | 0;
            continue ;
        case 2 :
            $$Buffer.add_char(b, /* '\\' */92);
            $$Buffer.add_char(b, nextChar);
            _i = i + 2 | 0;
            continue ;
        
      }
    };
  };
  loop(0);
  return $$Buffer.contents(b);
}

function parseConstant(p) {
  var match = p.token;
  var isNegative;
  if (typeof match === "number") {
    switch (match) {
      case /* Minus */34 :
          Res_parser.next(undefined, p);
          isNegative = true;
          break;
      case /* MinusDot */35 :
          isNegative = false;
          break;
      case /* Plus */36 :
          Res_parser.next(undefined, p);
          isNegative = false;
          break;
      default:
        isNegative = false;
    }
  } else {
    isNegative = false;
  }
  var s = p.token;
  var constant;
  var exit = 0;
  if (typeof s === "number") {
    exit = 1;
  } else {
    switch (s.TAG | 0) {
      case /* Codepoint */0 :
          constant = p.mode === /* ParseForTypeChecker */0 ? ({
                TAG: /* Pconst_char */1,
                _0: s.c
              }) : ({
                TAG: /* Pconst_string */2,
                _0: s.original,
                _1: "INTERNAL_RES_CHAR_CONTENTS"
              });
          break;
      case /* Int */1 :
          var i = s.i;
          var intTxt = isNegative ? "-" + i : i;
          constant = {
            TAG: /* Pconst_integer */0,
            _0: intTxt,
            _1: s.suffix
          };
          break;
      case /* Float */2 :
          var f = s.f;
          var floatTxt = isNegative ? "-" + f : f;
          constant = {
            TAG: /* Pconst_float */3,
            _0: floatTxt,
            _1: s.suffix
          };
          break;
      case /* String */3 :
          var s$1 = s._0;
          constant = p.mode === /* ParseForTypeChecker */0 ? ({
                TAG: /* Pconst_string */2,
                _0: s$1,
                _1: "js"
              }) : ({
                TAG: /* Pconst_string */2,
                _0: s$1,
                _1: undefined
              });
          break;
      default:
        exit = 1;
    }
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(s, p.breadcrumbs));
    constant = {
      TAG: /* Pconst_string */2,
      _0: "",
      _1: undefined
    };
  }
  Res_parser.next(undefined, p);
  return constant;
}

function parseTemplateConstant(prefix, p) {
  var startPos = p.startPos;
  Res_parser.nextTemplateLiteralToken(p);
  var txt = p.token;
  if (typeof txt !== "number" && txt.TAG === /* TemplateTail */7) {
    var txt$1 = txt._0;
    Res_parser.next(undefined, p);
    var txt$2 = p.mode === /* ParseForTypeChecker */0 ? parseTemplateStringLiteral(txt$1) : txt$1;
    return {
            TAG: /* Pconst_string */2,
            _0: txt$2,
            _1: prefix
          };
  }
  var skipTokens = function (_param) {
    while(true) {
      Res_parser.next(undefined, p);
      var match = p.token;
      if (match === 80) {
        Res_parser.next(undefined, p);
        return ;
      }
      _param = undefined;
      continue ;
    };
  };
  skipTokens(undefined);
  Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(stringInterpolationInPattern));
  return {
          TAG: /* Pconst_string */2,
          _0: "",
          _1: undefined
        };
}

function parseCommaDelimitedRegion(p, grammar, closing, f) {
  Res_parser.leaveBreadcrumb(p, grammar);
  var loop = function (_nodes) {
    while(true) {
      var nodes = _nodes;
      var node = Curry._1(f, p);
      if (node !== undefined) {
        var node$1 = Caml_option.valFromOption(node);
        var token = p.token;
        if (token === 25) {
          Res_parser.next(undefined, p);
          _nodes = {
            hd: node$1,
            tl: nodes
          };
          continue ;
        }
        if (Caml_obj.caml_equal(token, closing) || token === /* Eof */26) {
          return List.rev({
                      hd: node$1,
                      tl: nodes
                    });
        }
        if (Res_grammar.isListElement(grammar, p.token)) {
          Res_parser.expect(undefined, /* Comma */25, p);
          _nodes = {
            hd: node$1,
            tl: nodes
          };
          continue ;
        }
        if (!(p.token === /* Eof */26 || Caml_obj.caml_equal(p.token, closing) || shouldAbortListParse(p))) {
          Res_parser.expect(undefined, /* Comma */25, p);
        }
        if (p.token === /* Semicolon */8) {
          Res_parser.next(undefined, p);
        }
        _nodes = {
          hd: node$1,
          tl: nodes
        };
        continue ;
      }
      if (p.token === /* Eof */26 || Caml_obj.caml_equal(p.token, closing) || shouldAbortListParse(p)) {
        return List.rev(nodes);
      }
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
      Res_parser.next(undefined, p);
      continue ;
    };
  };
  var nodes = loop(/* [] */0);
  Res_parser.eatBreadcrumb(p);
  return nodes;
}

function parseCommaDelimitedReversedList(p, grammar, closing, f) {
  Res_parser.leaveBreadcrumb(p, grammar);
  var loop = function (_nodes) {
    while(true) {
      var nodes = _nodes;
      var node = Curry._1(f, p);
      if (node !== undefined) {
        var node$1 = Caml_option.valFromOption(node);
        var token = p.token;
        if (token === 25) {
          Res_parser.next(undefined, p);
          _nodes = {
            hd: node$1,
            tl: nodes
          };
          continue ;
        }
        if (Caml_obj.caml_equal(token, closing) || token === /* Eof */26) {
          return {
                  hd: node$1,
                  tl: nodes
                };
        }
        if (Res_grammar.isListElement(grammar, p.token)) {
          Res_parser.expect(undefined, /* Comma */25, p);
          _nodes = {
            hd: node$1,
            tl: nodes
          };
          continue ;
        }
        if (!(p.token === /* Eof */26 || Caml_obj.caml_equal(p.token, closing) || shouldAbortListParse(p))) {
          Res_parser.expect(undefined, /* Comma */25, p);
        }
        if (p.token === /* Semicolon */8) {
          Res_parser.next(undefined, p);
        }
        _nodes = {
          hd: node$1,
          tl: nodes
        };
        continue ;
      }
      if (p.token === /* Eof */26 || Caml_obj.caml_equal(p.token, closing) || shouldAbortListParse(p)) {
        return nodes;
      }
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
      Res_parser.next(undefined, p);
      continue ;
    };
  };
  var nodes = loop(/* [] */0);
  Res_parser.eatBreadcrumb(p);
  return nodes;
}

function parseDelimitedRegion(p, grammar, closing, f) {
  Res_parser.leaveBreadcrumb(p, grammar);
  var loop = function (_nodes) {
    while(true) {
      var nodes = _nodes;
      var node = Curry._1(f, p);
      if (node !== undefined) {
        _nodes = {
          hd: Caml_option.valFromOption(node),
          tl: nodes
        };
        continue ;
      }
      if (p.token === /* Eof */26 || Caml_obj.caml_equal(p.token, closing) || shouldAbortListParse(p)) {
        return List.rev(nodes);
      }
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
      Res_parser.next(undefined, p);
      continue ;
    };
  };
  var nodes = loop(/* [] */0);
  Res_parser.eatBreadcrumb(p);
  return nodes;
}

function parseRegion(p, grammar, f) {
  Res_parser.leaveBreadcrumb(p, grammar);
  var loop = function (_nodes) {
    while(true) {
      var nodes = _nodes;
      var node = Curry._1(f, p);
      if (node !== undefined) {
        _nodes = {
          hd: Caml_option.valFromOption(node),
          tl: nodes
        };
        continue ;
      }
      if (p.token === /* Eof */26 || shouldAbortListParse(p)) {
        return List.rev(nodes);
      }
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(p.token, p.breadcrumbs));
      Res_parser.next(undefined, p);
      continue ;
    };
  };
  var nodes = loop(/* [] */0);
  Res_parser.eatBreadcrumb(p);
  return nodes;
}

function parsePattern(aliasOpt, or_Opt, p) {
  var alias = aliasOpt !== undefined ? aliasOpt : true;
  var or_ = or_Opt !== undefined ? or_Opt : true;
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var token = p.token;
  var pat;
  var exit = 0;
  if (typeof token === "number") {
    switch (token) {
      case /* True */1 :
      case /* False */2 :
          exit = 2;
          break;
      case /* Underscore */12 :
          var endPos = p.endPos;
          var loc = {
            loc_start: startPos,
            loc_end: endPos,
            loc_ghost: false
          };
          Res_parser.next(undefined, p);
          pat = Ast_helper.Pat.any(loc, attrs, undefined);
          break;
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var match = p.token;
          if (match === 19) {
            Res_parser.next(undefined, p);
            var loc_loc_end = p.prevEndPos;
            var loc$1 = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var lid = $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: "()"
                }, loc$1);
            pat = Ast_helper.Pat.construct(loc$1, undefined, lid, undefined);
          } else {
            var pat$1 = parseConstrainedPattern(p);
            var match$1 = p.token;
            if (match$1 === 25) {
              Res_parser.next(undefined, p);
              pat = parseTuplePattern(attrs, pat$1, startPos, p);
            } else {
              Res_parser.expect(undefined, /* Rparen */19, p);
              var loc_loc_end$1 = p.prevEndPos;
              var loc$2 = {
                loc_start: startPos,
                loc_end: loc_loc_end$1,
                loc_ghost: false
              };
              pat = {
                ppat_desc: pat$1.ppat_desc,
                ppat_loc: loc$2,
                ppat_attributes: pat$1.ppat_attributes
              };
            }
          }
          break;
      case /* Lbracket */20 :
          pat = parseArrayPattern(attrs, p);
          break;
      case /* Lbrace */22 :
          pat = parseRecordPattern(attrs, p);
          break;
      case /* Exception */27 :
          Res_parser.next(undefined, p);
          var pat$2 = parsePattern(false, false, p);
          var loc_loc_end$2 = p.prevEndPos;
          var loc$3 = {
            loc_start: startPos,
            loc_end: loc_loc_end$2,
            loc_ghost: false
          };
          pat = Ast_helper.Pat.exception_(loc$3, attrs, pat$2);
          break;
      case /* Minus */34 :
      case /* Plus */36 :
          exit = 3;
          break;
      case /* Hash */44 :
          Res_parser.next(undefined, p);
          if (p.token === /* DotDotDot */6) {
            Res_parser.next(undefined, p);
            var ident = parseValuePath(p);
            var loc_loc_end$3 = ident.loc.loc_end;
            var loc$4 = {
              loc_start: startPos,
              loc_end: loc_loc_end$3,
              loc_ghost: false
            };
            pat = Ast_helper.Pat.type_(loc$4, attrs, ident);
          } else {
            var text = p.token;
            var match$2;
            if (typeof text === "number") {
              match$2 = parseIdent(variantIdent, startPos, p);
            } else {
              switch (text.TAG | 0) {
                case /* Int */1 :
                    var i = text.i;
                    if (text.suffix !== undefined) {
                      Res_parser.err(undefined, undefined, p, Res_diagnostics.message(polyVarIntWithSuffix(i)));
                    }
                    Res_parser.next(undefined, p);
                    match$2 = [
                      i,
                      {
                        loc_start: startPos,
                        loc_end: p.prevEndPos,
                        loc_ghost: false
                      }
                    ];
                    break;
                case /* String */3 :
                    var text$1 = text._0;
                    var text$2 = p.mode === /* ParseForTypeChecker */0 ? parseStringLiteral(text$1) : text$1;
                    Res_parser.next(undefined, p);
                    match$2 = [
                      text$2,
                      {
                        loc_start: startPos,
                        loc_end: p.prevEndPos,
                        loc_ghost: false
                      }
                    ];
                    break;
                default:
                  match$2 = parseIdent(variantIdent, startPos, p);
              }
            }
            var ident$1 = match$2[0];
            var match$3 = p.token;
            pat = match$3 === 18 ? parseVariantPatternArgs(p, ident$1, startPos, attrs) : Ast_helper.Pat.variant(match$2[1], attrs, ident$1, undefined);
          }
          break;
      case /* Lazy */47 :
          Res_parser.next(undefined, p);
          var pat$3 = parsePattern(false, false, p);
          var loc_loc_end$4 = p.prevEndPos;
          var loc$5 = {
            loc_start: startPos,
            loc_end: loc_loc_end$4,
            loc_ghost: false
          };
          pat = Ast_helper.Pat.lazy_(loc$5, attrs, pat$3);
          break;
      case /* Module */65 :
          pat = parseModulePattern(attrs, p);
          break;
      case /* Percent */77 :
          var extension = parseExtension(undefined, p);
          var loc_loc_end$5 = p.prevEndPos;
          var loc$6 = {
            loc_start: startPos,
            loc_end: loc_loc_end$5,
            loc_ghost: false
          };
          pat = Ast_helper.Pat.extension(loc$6, attrs, extension);
          break;
      case /* List */79 :
          Res_parser.next(undefined, p);
          pat = parseListPattern(startPos, attrs, p);
          break;
      case /* Backtick */80 :
          var constant = parseTemplateConstant("js", p);
          pat = Ast_helper.Pat.constant({
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              }, {
                hd: templateLiteralAttr,
                tl: /* [] */0
              }, constant);
          break;
      default:
        exit = 1;
    }
  } else {
    switch (token.TAG | 0) {
      case /* Codepoint */0 :
      case /* Int */1 :
      case /* Float */2 :
      case /* String */3 :
          exit = 3;
          break;
      case /* Lident */4 :
          var ident$2 = token._0;
          var endPos$1 = p.endPos;
          var loc$7 = {
            loc_start: startPos,
            loc_end: endPos$1,
            loc_ghost: false
          };
          Res_parser.next(undefined, p);
          var match$4 = p.token;
          if (match$4 === 80) {
            var constant$1 = parseTemplateConstant(ident$2, p);
            pat = Ast_helper.Pat.constant({
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                }, undefined, constant$1);
          } else {
            pat = Ast_helper.Pat.$$var(loc$7, attrs, $$Location.mkloc(ident$2, loc$7));
          }
          break;
      case /* Uident */5 :
          var constr = parseModuleLongIdent(false, p);
          var match$5 = p.token;
          pat = match$5 === 18 ? parseConstructorPatternArgs(p, constr, startPos, attrs) : Ast_helper.Pat.construct(constr.loc, attrs, constr, undefined);
          break;
      default:
        exit = 1;
    }
  }
  switch (exit) {
    case 1 :
        Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
        var match$6 = skipTokensAndMaybeRetry(p, Res_grammar.isAtomicPatternStart);
        pat = match$6 !== undefined ? parsePattern(undefined, undefined, p) : defaultPattern(undefined);
        break;
    case 2 :
        var endPos$2 = p.endPos;
        Res_parser.next(undefined, p);
        var loc$8 = {
          loc_start: startPos,
          loc_end: endPos$2,
          loc_ghost: false
        };
        pat = Ast_helper.Pat.construct(loc$8, undefined, $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: Res_token.toString(token)
                }, loc$8), undefined);
        break;
    case 3 :
        var c = parseConstant(p);
        var match$7 = p.token;
        if (match$7 === 5) {
          Res_parser.next(undefined, p);
          var c2 = parseConstant(p);
          pat = Ast_helper.Pat.interval({
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              }, undefined, c, c2);
        } else {
          pat = Ast_helper.Pat.constant({
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              }, undefined, c);
        }
        break;
    
  }
  var pat$4 = alias ? parseAliasPattern(attrs, pat, p) : pat;
  if (or_) {
    return parseOrPattern(pat$4, p);
  } else {
    return pat$4;
  }
}

function parseAttribute(p) {
  var match = p.token;
  if (match !== 75) {
    return ;
  }
  var startPos = p.startPos;
  Res_parser.next(undefined, p);
  var attrId = parseAttributeId(startPos, p);
  var payload = parsePayload(p);
  return [
          attrId,
          payload
        ];
}

function parseModuleType(es6ArrowOpt, with_Opt, p) {
  var es6Arrow = es6ArrowOpt !== undefined ? es6ArrowOpt : true;
  var with_ = with_Opt !== undefined ? with_Opt : true;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var modty;
  if (es6Arrow && isEs6ArrowFunctor(p)) {
    modty = parseFunctorModuleType(p);
  } else {
    var modty$1 = parseAtomicModuleType(p);
    var match = p.token;
    if (match === 57 && es6Arrow === true) {
      Res_parser.next(undefined, p);
      var rhs = parseModuleType(undefined, false, p);
      var str = $$Location.mknoloc("_");
      var loc_loc_start = modty$1.pmty_loc.loc_start;
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: loc_loc_start,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      modty = Ast_helper.Mty.functor_(loc, undefined, str, modty$1, rhs);
    } else {
      modty = modty$1;
    }
  }
  var moduleType_pmty_desc = modty.pmty_desc;
  var moduleType_pmty_loc = modty.pmty_loc;
  var moduleType_pmty_attributes = List.concat({
        hd: modty.pmty_attributes,
        tl: {
          hd: attrs,
          tl: /* [] */0
        }
      });
  var moduleType = {
    pmty_desc: moduleType_pmty_desc,
    pmty_loc: moduleType_pmty_loc,
    pmty_attributes: moduleType_pmty_attributes
  };
  if (with_) {
    return parseWithConstraints(moduleType, p);
  } else {
    return moduleType;
  }
}

function parseModuleBindings(attrs, startPos, p) {
  var first = parseModuleBinding(attrs, startPos, p);
  var _acc = {
    hd: first,
    tl: /* [] */0
  };
  while(true) {
    var acc = _acc;
    var startPos$1 = p.startPos;
    var attrs$1 = parseAttributesAndBinding(p);
    var match = p.token;
    if (match !== 10) {
      return List.rev(acc);
    }
    Res_parser.next(undefined, p);
    Res_parser.optional(p, /* Module */65);
    var modBinding = parseModuleBinding(attrs$1, startPos$1, p);
    _acc = {
      hd: modBinding,
      tl: acc
    };
    continue ;
  };
}

function parseModuleBinding(attrs, startPos, p) {
  var ident = p.token;
  var name;
  var exit = 0;
  if (typeof ident === "number" || ident.TAG !== /* Uident */5) {
    exit = 1;
  } else {
    var startPos$1 = p.startPos;
    Res_parser.next(undefined, p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos$1,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    name = $$Location.mkloc(ident._0, loc);
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
    name = $$Location.mknoloc("_");
  }
  var body = parseModuleBindingBody(p);
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Mb.mk(loc$1, attrs, undefined, undefined, name, body);
}

function parseConstrainedPattern(p) {
  var pat = parsePattern(undefined, undefined, p);
  var match = p.token;
  if (match !== 24) {
    return pat;
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = pat.ppat_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Pat.constraint_(loc, undefined, pat, typ);
}

function parseLidentList(p) {
  var _ls = /* [] */0;
  while(true) {
    var ls = _ls;
    var lident = p.token;
    if (typeof lident === "number") {
      return List.rev(ls);
    }
    if (lident.TAG !== /* Lident */4) {
      return List.rev(ls);
    }
    var loc_loc_start = p.startPos;
    var loc_loc_end = p.endPos;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    _ls = {
      hd: $$Location.mkloc(lident._0, loc),
      tl: ls
    };
    continue ;
  };
}

function parseTypExpr(attrs, es6ArrowOpt, aliasOpt, p) {
  var es6Arrow = es6ArrowOpt !== undefined ? es6ArrowOpt : true;
  var alias = aliasOpt !== undefined ? aliasOpt : true;
  var startPos = p.startPos;
  var attrs$1 = attrs !== undefined ? attrs : parseRegion(p, /* Attribute */50, parseAttribute);
  var typ;
  if (es6Arrow && isEs6ArrowType(p)) {
    typ = parseEs6ArrowType(attrs$1, p);
  } else {
    var typ$1 = parseAtomicTypExpr(attrs$1, p);
    typ = parseArrowTypeRest(es6Arrow, startPos, typ$1, p);
  }
  if (alias) {
    return parseTypeAlias(p, typ);
  } else {
    return typ;
  }
}

function parseConstrainedOrCoercedExpr(p) {
  var expr = parseExpr(undefined, p);
  var match = p.token;
  if (typeof match !== "number") {
    return expr;
  }
  if (match !== 24) {
    if (match !== 40) {
      return expr;
    } else {
      return parseCoercedExpr(expr, p);
    }
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = expr.pexp_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var expr$1 = Ast_helper.Exp.constraint_(loc, undefined, expr, typ);
  var match$1 = p.token;
  if (match$1 === 40) {
    return parseCoercedExpr(expr$1, p);
  } else {
    return expr$1;
  }
}

function parseNonSpreadPattern(msg, p) {
  var match = p.token;
  if (match === 6) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message(msg));
    Res_parser.next(undefined, p);
  }
  var token = p.token;
  if (!Res_grammar.isPatternStart(token)) {
    return ;
  }
  var pat = parsePattern(undefined, undefined, p);
  var match$1 = p.token;
  if (match$1 !== 24) {
    return pat;
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = pat.ppat_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Pat.constraint_(loc, undefined, pat, typ);
}

function parseTypeAlias(p, typ) {
  var match = p.token;
  if (match !== 3) {
    return typ;
  }
  Res_parser.next(undefined, p);
  Res_parser.expect(undefined, /* SingleQuote */13, p);
  var match$1 = parseLident(p);
  return Ast_helper.Typ.alias({
              loc_start: typ.ptyp_loc.loc_start,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, undefined, typ, match$1[0]);
}

function parseFieldDeclarationRegion(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var mut = Res_parser.optional(p, /* Mutable */62) ? /* Mutable */1 : /* Immutable */0;
  var match = p.token;
  if (typeof match === "number") {
    return ;
  }
  if (match.TAG !== /* Lident */4) {
    return ;
  }
  var match$1 = parseLident(p);
  var name = $$Location.mkloc(match$1[0], match$1[1]);
  var match$2 = p.token;
  var typ = match$2 === 24 ? (Res_parser.next(undefined, p), parsePolyTypeExpr(p)) : Ast_helper.Typ.constr(name.loc, undefined, {
          txt: {
            TAG: /* Lident */0,
            _0: name.txt
          },
          loc: name.loc
        }, /* [] */0);
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Type.field(loc, attrs, undefined, mut, name, typ);
}

function parseFieldDeclaration(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var mut = Res_parser.optional(p, /* Mutable */62) ? /* Mutable */1 : /* Immutable */0;
  var match = parseLident(p);
  var name = $$Location.mkloc(match[0], match[1]);
  var match$1 = p.token;
  var typ = match$1 === 24 ? (Res_parser.next(undefined, p), parsePolyTypeExpr(p)) : Ast_helper.Typ.constr(name.loc, undefined, {
          txt: {
            TAG: /* Lident */0,
            _0: name.txt
          },
          loc: name.loc
        }, /* [] */0);
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Type.field(loc, attrs, undefined, mut, name, typ);
}

function parseArrowTypeRest(es6Arrow, startPos, typ, p) {
  var token = p.token;
  if (typeof token !== "number") {
    return typ;
  }
  if (!(token === 58 || token === 57)) {
    return typ;
  }
  if (es6Arrow !== true) {
    return typ;
  }
  if (token === /* MinusGreater */58) {
    Res_parser.expect(undefined, /* EqualGreater */57, p);
  }
  Res_parser.next(undefined, p);
  var returnType = parseTypExpr(undefined, undefined, false, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Typ.arrow(loc, undefined, /* Nolabel */0, typ, returnType);
}

function parseStringFieldDeclaration(p) {
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var name = p.token;
  if (typeof name === "number") {
    if (name !== /* DotDotDot */6) {
      return ;
    }
    Res_parser.next(undefined, p);
    var typ = parseTypExpr(undefined, undefined, undefined, p);
    return {
            TAG: /* Oinherit */1,
            _0: typ
          };
  } else {
    switch (name.TAG | 0) {
      case /* String */3 :
          var nameStartPos = p.startPos;
          var nameEndPos = p.endPos;
          Res_parser.next(undefined, p);
          var fieldName = $$Location.mkloc(name._0, {
                loc_start: nameStartPos,
                loc_end: nameEndPos,
                loc_ghost: false
              });
          Res_parser.expect(/* TypeExpression */20, /* Colon */24, p);
          var typ$1 = parsePolyTypeExpr(p);
          return {
                  TAG: /* Otag */0,
                  _0: fieldName,
                  _1: attrs,
                  _2: typ$1
                };
      case /* Lident */4 :
          var name$1 = name._0;
          var nameLoc_loc_start = p.startPos;
          var nameLoc_loc_end = p.endPos;
          var nameLoc = {
            loc_start: nameLoc_loc_start,
            loc_end: nameLoc_loc_end,
            loc_ghost: false
          };
          Res_parser.err(undefined, undefined, p, Res_diagnostics.message(objectQuotedFieldName(name$1)));
          Res_parser.next(undefined, p);
          var fieldName$1 = $$Location.mkloc(name$1, nameLoc);
          Res_parser.expect(/* TypeExpression */20, /* Colon */24, p);
          var typ$2 = parsePolyTypeExpr(p);
          return {
                  TAG: /* Otag */0,
                  _0: fieldName$1,
                  _1: attrs,
                  _2: typ$2
                };
      default:
        return ;
    }
  }
}

function parseTagSpec(p) {
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (match === 44) {
    return parsePolymorphicVariantTypeSpecHash(attrs, false, p);
  }
  var typ = parseTypExpr(attrs, undefined, undefined, p);
  return {
          TAG: /* Rinherit */1,
          _0: typ
        };
}

function parseTagSpecFulls(p) {
  var match = p.token;
  if (typeof match !== "number") {
    return /* [] */0;
  }
  if (!(match > 41 || match < 21)) {
    return /* [] */0;
  }
  if (match !== 17) {
    return /* [] */0;
  }
  Res_parser.next(undefined, p);
  var rowField = parseTagSpecFull(p);
  return {
          hd: rowField,
          tl: parseTagSpecFulls(p)
        };
}

function parseTagSpecFull(p) {
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (match === 44) {
    return parsePolymorphicVariantTypeSpecHash(attrs, true, p);
  }
  var typ = parseTypExpr(attrs, undefined, undefined, p);
  return {
          TAG: /* Rinherit */1,
          _0: typ
        };
}

function parseTagSpecFirst(p) {
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (typeof match === "number") {
    if (match !== 17) {
      if (match === 44) {
        return {
                hd: parsePolymorphicVariantTypeSpecHash(attrs, false, p),
                tl: /* [] */0
              };
      }
      
    } else {
      Res_parser.next(undefined, p);
      return {
              hd: parseTagSpec(p),
              tl: /* [] */0
            };
    }
  }
  var typ = parseTypExpr(attrs, undefined, undefined, p);
  var match$1 = p.token;
  if (match$1 === 21) {
    return {
            hd: {
              TAG: /* Rinherit */1,
              _0: typ
            },
            tl: /* [] */0
          };
  } else {
    Res_parser.expect(undefined, /* Bar */17, p);
    return {
            hd: {
              TAG: /* Rinherit */1,
              _0: typ
            },
            tl: {
              hd: parseTagSpec(p),
              tl: /* [] */0
            }
          };
  }
}

function parseTagSpecs(p) {
  var match = p.token;
  if (match !== 17) {
    return /* [] */0;
  }
  Res_parser.next(undefined, p);
  var rowField = parseTagSpec(p);
  return {
          hd: rowField,
          tl: parseTagSpecs(p)
        };
}

function parseTagNames(p) {
  if (p.token === /* GreaterThan */41) {
    Res_parser.next(undefined, p);
    return parseRegion(p, /* TagNames */57, parseTagName);
  } else {
    return /* [] */0;
  }
}

function parseRecordRow(p) {
  var match = p.token;
  if (match === 6) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message(recordExprSpread));
    Res_parser.next(undefined, p);
  }
  var match$1 = p.token;
  if (typeof match$1 === "number") {
    return ;
  }
  switch (match$1.TAG | 0) {
    case /* Lident */4 :
    case /* Uident */5 :
        break;
    default:
      return ;
  }
  var startToken = p.token;
  var field = parseValuePath(p);
  var match$2 = p.token;
  if (match$2 === 24) {
    Res_parser.next(undefined, p);
    var fieldExpr = parseExpr(undefined, p);
    return [
            field,
            fieldExpr
          ];
  }
  var value = Ast_helper.Exp.ident(field.loc, undefined, field);
  var value$1;
  value$1 = typeof startToken === "number" || startToken.TAG !== /* Uident */5 ? value : removeModuleNameFromPunnedFieldValue(value);
  return [
          field,
          value$1
        ];
}

function parsePolyTypeExpr(p) {
  var startPos = p.startPos;
  var match = p.token;
  if (match !== 13) {
    return parseTypExpr(undefined, undefined, undefined, p);
  }
  var vars = parseTypeVarList(p);
  if (vars) {
    var _v1 = vars.hd;
    if (vars.tl) {
      Res_parser.expect(undefined, /* Dot */4, p);
      var typ = parseTypExpr(undefined, undefined, undefined, p);
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: startPos,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      return Ast_helper.Typ.poly(loc, undefined, vars, typ);
    }
    var match$1 = p.token;
    if (typeof match$1 === "number") {
      if (match$1 !== 4) {
        if (match$1 === 57) {
          Res_parser.next(undefined, p);
          var typ$1 = Ast_helper.Typ.$$var(_v1.loc, undefined, _v1.txt);
          var returnType = parseTypExpr(undefined, undefined, false, p);
          var loc_loc_start = typ$1.ptyp_loc.loc_start;
          var loc_loc_end$1 = p.prevEndPos;
          var loc$1 = {
            loc_start: loc_loc_start,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          return Ast_helper.Typ.arrow(loc$1, undefined, /* Nolabel */0, typ$1, returnType);
        }
        
      } else {
        Res_parser.next(undefined, p);
        var typ$2 = parseTypExpr(undefined, undefined, undefined, p);
        var loc_loc_end$2 = p.prevEndPos;
        var loc$2 = {
          loc_start: startPos,
          loc_end: loc_loc_end$2,
          loc_ghost: false
        };
        return Ast_helper.Typ.poly(loc$2, undefined, vars, typ$2);
      }
    }
    return Ast_helper.Typ.$$var(_v1.loc, undefined, _v1.txt);
  }
  throw {
        RE_EXN_ID: "Assert_failure",
        _1: [
          "res_core.res",
          4299,
          11
        ],
        Error: new Error()
      };
}

function overParseConstrainedOrCoercedOrArrowExpression(p, expr) {
  var match = p.token;
  if (typeof match !== "number") {
    return expr;
  }
  if (match !== 24) {
    if (match !== 40) {
      return expr;
    } else {
      return parseCoercedExpr(expr, p);
    }
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, false, undefined, p);
  var match$1 = p.token;
  if (match$1 === 57) {
    Res_parser.next(undefined, p);
    var body = parseExpr(undefined, p);
    var longident = expr.pexp_desc;
    var pat;
    var exit = 0;
    if (typeof longident === "number" || longident.TAG !== /* Pexp_ident */0) {
      exit = 1;
    } else {
      var longident$1 = longident._0;
      pat = Ast_helper.Pat.$$var(expr.pexp_loc, undefined, $$Location.mkloc($$String.concat(".", Longident.flatten(longident$1.txt)), longident$1.loc));
    }
    if (exit === 1) {
      pat = Ast_helper.Pat.$$var(expr.pexp_loc, undefined, $$Location.mkloc("pattern", expr.pexp_loc));
    }
    var arrow1 = Ast_helper.Exp.fun_({
          loc_start: expr.pexp_loc.loc_start,
          loc_end: body.pexp_loc.loc_end,
          loc_ghost: false
        }, undefined, /* Nolabel */0, undefined, pat, Ast_helper.Exp.constraint_(undefined, undefined, body, typ));
    var arrow2 = Ast_helper.Exp.fun_({
          loc_start: expr.pexp_loc.loc_start,
          loc_end: body.pexp_loc.loc_end,
          loc_ghost: false
        }, undefined, /* Nolabel */0, undefined, Ast_helper.Pat.constraint_(undefined, undefined, pat, typ), body);
    var msg = Res_doc.toString(80, Res_doc.breakableGroup(true, Res_doc.concat({
                  hd: Res_doc.text("Did you mean to annotate the parameter type or the return type?"),
                  tl: {
                    hd: Res_doc.indent(Res_doc.concat({
                              hd: Res_doc.line,
                              tl: {
                                hd: Res_doc.text("1) "),
                                tl: {
                                  hd: Res_printer.printExpression(arrow1, Res_comments_table.empty),
                                  tl: {
                                    hd: Res_doc.line,
                                    tl: {
                                      hd: Res_doc.text("2) "),
                                      tl: {
                                        hd: Res_printer.printExpression(arrow2, Res_comments_table.empty),
                                        tl: /* [] */0
                                      }
                                    }
                                  }
                                }
                              }
                            })),
                    tl: /* [] */0
                  }
                })));
    Res_parser.err(expr.pexp_loc.loc_start, body.pexp_loc.loc_end, p, Res_diagnostics.message(msg));
    return arrow1;
  }
  var loc_loc_start = expr.pexp_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var expr$1 = Ast_helper.Exp.constraint_(loc, undefined, expr, typ);
  Res_parser.err(expr$1.pexp_loc.loc_start, typ.ptyp_loc.loc_end, p, Res_diagnostics.message(Res_doc.toString(80, Res_doc.breakableGroup(true, Res_doc.concat({
                        hd: Res_doc.text("Expressions with type constraints need to be wrapped in parens:"),
                        tl: {
                          hd: Res_doc.indent(Res_doc.concat({
                                    hd: Res_doc.line,
                                    tl: {
                                      hd: Res_printer.addParens(Res_printer.printExpression(expr$1, Res_comments_table.empty)),
                                      tl: /* [] */0
                                    }
                                  })),
                          tl: /* [] */0
                        }
                      })))));
  return expr$1;
}

function parseExpr(contextOpt, p) {
  var context = contextOpt !== undefined ? contextOpt : /* OrdinaryExpr */0;
  var expr = parseOperandExpr(context, p);
  var expr$1 = parseBinaryExpr(context, expr, p, 1);
  return parseTernaryExpr(expr$1, p);
}

function parsePayload(p) {
  var match = p.token;
  if (match !== 18) {
    return {
            TAG: /* PStr */0,
            _0: /* [] */0
          };
  }
  if (p.startPos.pos_cnum !== p.prevEndPos.pos_cnum) {
    return {
            TAG: /* PStr */0,
            _0: /* [] */0
          };
  }
  Res_parser.leaveBreadcrumb(p, /* AttributePayload */56);
  Res_parser.next(undefined, p);
  var match$1 = p.token;
  if (typeof match$1 === "number") {
    if (match$1 !== 24) {
      if (match$1 === 49) {
        Res_parser.next(undefined, p);
        var pattern = parsePattern(undefined, undefined, p);
        var match$2 = p.token;
        var expr;
        var exit = 0;
        if (typeof match$2 === "number" && !(match$2 !== 50 && match$2 !== 56)) {
          exit = 2;
        } else {
          expr = undefined;
        }
        if (exit === 2) {
          Res_parser.next(undefined, p);
          expr = parseExpr(undefined, p);
        }
        Res_parser.expect(undefined, /* Rparen */19, p);
        Res_parser.eatBreadcrumb(p);
        return {
                TAG: /* PPat */3,
                _0: pattern,
                _1: expr
              };
      }
      
    } else {
      Res_parser.next(undefined, p);
      var payload = Res_grammar.isSignatureItemStart(p.token) ? ({
            TAG: /* PSig */1,
            _0: parseDelimitedRegion(p, /* Signature */46, /* Rparen */19, parseSignatureItemRegion)
          }) : ({
            TAG: /* PTyp */2,
            _0: parseTypExpr(undefined, undefined, undefined, p)
          });
      Res_parser.expect(undefined, /* Rparen */19, p);
      Res_parser.eatBreadcrumb(p);
      return payload;
    }
  }
  var items = parseDelimitedRegion(p, /* Structure */48, /* Rparen */19, parseStructureItemRegion);
  Res_parser.expect(undefined, /* Rparen */19, p);
  Res_parser.eatBreadcrumb(p);
  return {
          TAG: /* PStr */0,
          _0: items
        };
}

function parseAttributeId(startPos, p) {
  var loop = function (p, _acc) {
    while(true) {
      var acc = _acc;
      var token = p.token;
      var exit = 0;
      if (typeof token === "number") {
        exit = 2;
      } else {
        switch (token.TAG | 0) {
          case /* Lident */4 :
          case /* Uident */5 :
              exit = 1;
              break;
          default:
            exit = 2;
        }
      }
      switch (exit) {
        case 1 :
            Res_parser.next(undefined, p);
            var id = acc + token._0;
            var match = p.token;
            if (match !== 4) {
              return id;
            }
            Res_parser.next(undefined, p);
            _acc = id + ".";
            continue ;
        case 2 :
            if (Res_token.isKeyword(token)) {
              Res_parser.next(undefined, p);
              var id$1 = acc + Res_token.toString(token);
              var match$1 = p.token;
              if (match$1 !== 4) {
                return id$1;
              }
              Res_parser.next(undefined, p);
              _acc = id$1 + ".";
              continue ;
            }
            Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
            return acc;
        
      }
    };
  };
  var id = loop(p, "");
  var endPos = p.prevEndPos;
  return $$Location.mkloc(id, {
              loc_start: startPos,
              loc_end: endPos,
              loc_ghost: false
            });
}

function parseConstrDeclArgs(p) {
  var match = p.token;
  var constrArgs;
  if (match === 18) {
    Res_parser.next(undefined, p);
    var match$1 = p.token;
    if (match$1 === 22) {
      var lbrace = p.startPos;
      Res_parser.next(undefined, p);
      var startPos = p.startPos;
      var match$2 = p.token;
      var exit = 0;
      if (typeof match$2 === "number") {
        if (match$2 >= 6) {
          if (match$2 >= 7) {
            exit = 1;
          } else {
            var dotdotdotStart = p.startPos;
            var dotdotdotEnd = p.endPos;
            Res_parser.next(undefined, p);
            var typ = parseTypExpr(undefined, undefined, undefined, p);
            var match$3 = p.token;
            if (match$3 === 23) {
              Res_parser.err(dotdotdotStart, dotdotdotEnd, p, Res_diagnostics.message(sameTypeSpread));
              Res_parser.next(undefined, p);
            } else {
              Res_parser.expect(undefined, /* Comma */25, p);
            }
            var match$4 = p.token;
            if (typeof match$4 !== "number" && match$4.TAG === /* Lident */4) {
              Res_parser.err(dotdotdotStart, dotdotdotEnd, p, Res_diagnostics.message(spreadInRecordDeclaration));
            }
            var fields_0 = {
              TAG: /* Oinherit */1,
              _0: typ
            };
            var fields_1 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
            var fields = {
              hd: fields_0,
              tl: fields_1
            };
            Res_parser.expect(undefined, /* Rbrace */23, p);
            var loc_loc_end = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var typ$1 = parseTypeAlias(p, Ast_helper.Typ.object_(loc, undefined, fields, /* Closed */0));
            var typ$2 = parseArrowTypeRest(true, startPos, typ$1, p);
            Res_parser.optional(p, /* Comma */25);
            var moreArgs = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
            Res_parser.expect(undefined, /* Rparen */19, p);
            constrArgs = {
              TAG: /* Pcstr_tuple */0,
              _0: {
                hd: typ$2,
                tl: moreArgs
              }
            };
          }
        } else if (match$2 >= 4) {
          var match$5 = p.token;
          var closedFlag = typeof match$5 === "number" ? (
              match$5 !== 4 ? (
                  match$5 !== 5 ? /* Closed */0 : (Res_parser.next(undefined, p), /* Open */1)
                ) : (Res_parser.next(undefined, p), /* Closed */0)
            ) : /* Closed */0;
          var fields$1 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
          Res_parser.expect(undefined, /* Rbrace */23, p);
          var loc_loc_end$1 = p.prevEndPos;
          var loc$1 = {
            loc_start: startPos,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          var typ$3 = Ast_helper.Typ.object_(loc$1, /* [] */0, fields$1, closedFlag);
          Res_parser.optional(p, /* Comma */25);
          var moreArgs$1 = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
          Res_parser.expect(undefined, /* Rparen */19, p);
          constrArgs = {
            TAG: /* Pcstr_tuple */0,
            _0: {
              hd: typ$3,
              tl: moreArgs$1
            }
          };
        } else {
          exit = 1;
        }
      } else {
        exit = 1;
      }
      if (exit === 1) {
        var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
        var match$6 = p.token;
        var exit$1 = 0;
        if (typeof match$6 === "number" || match$6.TAG !== /* String */3) {
          exit$1 = 2;
        } else {
          var fields$2;
          if (attrs) {
            Res_parser.leaveBreadcrumb(p, /* StringFieldDeclarations */37);
            var field = parseStringFieldDeclaration(p);
            var field$1;
            if (field !== undefined) {
              field$1 = field;
            } else {
              throw {
                    RE_EXN_ID: "Assert_failure",
                    _1: [
                      "res_core.res",
                      5016,
                      24
                    ],
                    Error: new Error()
                  };
            }
            var match$7 = p.token;
            if (typeof match$7 === "number") {
              if (match$7 >= 24) {
                if (match$7 >= 27) {
                  Res_parser.expect(undefined, /* Comma */25, p);
                } else {
                  switch (match$7) {
                    case /* Colon */24 :
                        Res_parser.expect(undefined, /* Comma */25, p);
                        break;
                    case /* Comma */25 :
                        Res_parser.next(undefined, p);
                        break;
                    case /* Eof */26 :
                        break;
                    
                  }
                }
              } else if (match$7 >= 23) {
                
              } else {
                Res_parser.expect(undefined, /* Comma */25, p);
              }
            } else {
              Res_parser.expect(undefined, /* Comma */25, p);
            }
            Res_parser.eatBreadcrumb(p);
            var first;
            first = field$1.TAG === /* Otag */0 ? ({
                  TAG: /* Otag */0,
                  _0: field$1._0,
                  _1: attrs,
                  _2: field$1._2
                }) : ({
                  TAG: /* Oinherit */1,
                  _0: field$1._0
                });
            fields$2 = {
              hd: first,
              tl: parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration)
            };
          } else {
            fields$2 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
          }
          Res_parser.expect(undefined, /* Rbrace */23, p);
          var loc_loc_end$2 = p.prevEndPos;
          var loc$2 = {
            loc_start: startPos,
            loc_end: loc_loc_end$2,
            loc_ghost: false
          };
          var typ$4 = parseTypeAlias(p, Ast_helper.Typ.object_(loc$2, /* [] */0, fields$2, /* Closed */0));
          var typ$5 = parseArrowTypeRest(true, startPos, typ$4, p);
          Res_parser.optional(p, /* Comma */25);
          var moreArgs$2 = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
          Res_parser.expect(undefined, /* Rparen */19, p);
          constrArgs = {
            TAG: /* Pcstr_tuple */0,
            _0: {
              hd: typ$5,
              tl: moreArgs$2
            }
          };
        }
        if (exit$1 === 2) {
          var fields$3;
          if (attrs) {
            var field$2 = parseFieldDeclaration(p);
            Res_parser.expect(undefined, /* Comma */25, p);
            var first_pld_name = field$2.pld_name;
            var first_pld_mutable = field$2.pld_mutable;
            var first_pld_type = field$2.pld_type;
            var first_pld_loc = field$2.pld_loc;
            var first$1 = {
              pld_name: first_pld_name,
              pld_mutable: first_pld_mutable,
              pld_type: first_pld_type,
              pld_loc: first_pld_loc,
              pld_attributes: attrs
            };
            fields$3 = {
              hd: first$1,
              tl: parseCommaDelimitedRegion(p, /* FieldDeclarations */38, /* Rbrace */23, parseFieldDeclarationRegion)
            };
          } else {
            fields$3 = parseCommaDelimitedRegion(p, /* FieldDeclarations */38, /* Rbrace */23, parseFieldDeclarationRegion);
          }
          if (fields$3) {
            
          } else {
            Res_parser.err(lbrace, undefined, p, Res_diagnostics.message("An inline record declaration needs at least one field"));
          }
          Res_parser.expect(undefined, /* Rbrace */23, p);
          Res_parser.optional(p, /* Comma */25);
          Res_parser.expect(undefined, /* Rparen */19, p);
          constrArgs = {
            TAG: /* Pcstr_record */1,
            _0: fields$3
          };
        }
        
      }
      
    } else {
      var args = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
      Res_parser.expect(undefined, /* Rparen */19, p);
      constrArgs = {
        TAG: /* Pcstr_tuple */0,
        _0: args
      };
    }
  } else {
    constrArgs = {
      TAG: /* Pcstr_tuple */0,
      _0: /* [] */0
    };
  }
  var match$8 = p.token;
  var res = match$8 === 24 ? (Res_parser.next(undefined, p), parseTypExpr(undefined, undefined, undefined, p)) : undefined;
  return [
          constrArgs,
          res
        ];
}

function parsePackageConstraint(p) {
  var match = p.token;
  if (match !== 10) {
    return ;
  }
  Res_parser.next(undefined, p);
  Res_parser.expect(undefined, /* Typ */60, p);
  var typeConstr = parseValuePath(p);
  Res_parser.expect(undefined, /* Equal */14, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  return [
          typeConstr,
          typ
        ];
}

function parseConstrDef(parseAttrs, p) {
  var attrs = parseAttrs ? parseRegion(p, /* Attribute */50, parseAttribute) : /* [] */0;
  var name = p.token;
  var name$1;
  var exit = 0;
  if (typeof name === "number" || name.TAG !== /* Uident */5) {
    exit = 1;
  } else {
    var loc_loc_start = p.startPos;
    var loc_loc_end = p.endPos;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    name$1 = $$Location.mkloc(name._0, loc);
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(name));
    name$1 = $$Location.mknoloc("_");
  }
  var match = p.token;
  var kind;
  if (typeof match === "number") {
    switch (match) {
      case /* Equal */14 :
          Res_parser.next(undefined, p);
          var longident = parseModuleLongIdent(false, p);
          kind = {
            TAG: /* Pext_rebind */1,
            _0: longident
          };
          break;
      case /* Lparen */18 :
          var match$1 = parseConstrDeclArgs(p);
          kind = {
            TAG: /* Pext_decl */0,
            _0: match$1[0],
            _1: match$1[1]
          };
          break;
      case /* EqualEqual */15 :
      case /* EqualEqualEqual */16 :
      case /* Bar */17 :
      case /* Rparen */19 :
      case /* Lbracket */20 :
      case /* Rbracket */21 :
      case /* Lbrace */22 :
      case /* Rbrace */23 :
          kind = {
            TAG: /* Pext_decl */0,
            _0: {
              TAG: /* Pcstr_tuple */0,
              _0: /* [] */0
            },
            _1: undefined
          };
          break;
      case /* Colon */24 :
          Res_parser.next(undefined, p);
          var typ = parseTypExpr(undefined, undefined, undefined, p);
          kind = {
            TAG: /* Pext_decl */0,
            _0: {
              TAG: /* Pcstr_tuple */0,
              _0: /* [] */0
            },
            _1: typ
          };
          break;
      default:
        kind = {
          TAG: /* Pext_decl */0,
          _0: {
            TAG: /* Pcstr_tuple */0,
            _0: /* [] */0
          },
          _1: undefined
        };
    }
  } else {
    kind = {
      TAG: /* Pext_decl */0,
      _0: {
        TAG: /* Pcstr_tuple */0,
        _0: /* [] */0
      },
      _1: undefined
    };
  }
  return [
          attrs,
          name$1,
          kind
        ];
}

function parseTypeVarList(p) {
  var _vars = /* [] */0;
  while(true) {
    var vars = _vars;
    var match = p.token;
    if (match !== 13) {
      return List.rev(vars);
    }
    Res_parser.next(undefined, p);
    var match$1 = parseLident(p);
    var $$var = $$Location.mkloc(match$1[0], match$1[1]);
    _vars = {
      hd: $$var,
      tl: vars
    };
    continue ;
  };
}

function parseModuleExpr(p) {
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var modExpr = isEs6ArrowFunctor(p) ? parseFunctorModuleExpr(p) : parsePrimaryModExpr(p);
  return {
          pmod_desc: modExpr.pmod_desc,
          pmod_loc: modExpr.pmod_loc,
          pmod_attributes: List.concat({
                hd: modExpr.pmod_attributes,
                tl: {
                  hd: attrs,
                  tl: /* [] */0
                }
              })
        };
}

function parseTypeConstructorDeclaration(startPos, p) {
  Res_parser.leaveBreadcrumb(p, /* ConstructorDeclaration */35);
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var uident = p.token;
  if (typeof uident !== "number" && uident.TAG === /* Uident */5) {
    var uidentLoc_loc_start = p.startPos;
    var uidentLoc_loc_end = p.endPos;
    var uidentLoc = {
      loc_start: uidentLoc_loc_start,
      loc_end: uidentLoc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    var match = parseConstrDeclArgs(p);
    Res_parser.eatBreadcrumb(p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return Ast_helper.Type.constructor(loc, attrs, undefined, match[0], match[1], $$Location.mkloc(uident._0, uidentLoc));
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(uident));
  return Ast_helper.Type.constructor(undefined, undefined, undefined, undefined, undefined, $$Location.mknoloc("_"));
}

function parseConstrainedPatternRegion(p) {
  var token = p.token;
  if (Res_grammar.isPatternStart(token)) {
    return parseConstrainedPattern(p);
  }
  
}

function parseExprBlock(first, p) {
  Res_parser.leaveBreadcrumb(p, /* ExprBlock */10);
  var item = first !== undefined ? first : parseExprBlockItem(p);
  parseNewlineOrSemicolonExprBlock(p);
  var blockExpr;
  if (Res_grammar.isBlockExprStart(p.token)) {
    var next = parseExprBlockItem(p);
    var init = item.pexp_loc;
    var loc_loc_start = init.loc_start;
    var loc_loc_end = next.pexp_loc.loc_end;
    var loc_loc_ghost = init.loc_ghost;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: loc_loc_ghost
    };
    blockExpr = Ast_helper.Exp.sequence(loc, undefined, item, next);
  } else {
    blockExpr = item;
  }
  Res_parser.eatBreadcrumb(p);
  return overParseConstrainedOrCoercedOrArrowExpression(p, blockExpr);
}

function parsePatternRegion(p) {
  var token = p.token;
  if (token === 6) {
    Res_parser.next(undefined, p);
    return [
            true,
            parseConstrainedPattern(p)
          ];
  } else if (Res_grammar.isPatternStart(token)) {
    return [
            false,
            parseConstrainedPattern(p)
          ];
  } else {
    return ;
  }
}

function parseSpreadExprRegion(p) {
  var token = p.token;
  if (token !== 6) {
    if (Res_grammar.isExprStart(token)) {
      return [
              false,
              parseConstrainedOrCoercedExpr(p)
            ];
    } else {
      return ;
    }
  }
  Res_parser.next(undefined, p);
  var expr = parseConstrainedOrCoercedExpr(p);
  return [
          true,
          expr
        ];
}

function parsePackageType(startPos, attrs, p) {
  var modTypePath = parseModuleLongIdent(true, p);
  var match = p.token;
  if (typeof match !== "number" && match.TAG === /* Lident */4 && match._0 === "with") {
    Res_parser.next(undefined, p);
    var constraints = parsePackageConstraints(p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return Ast_helper.Typ.$$package(loc, attrs, modTypePath, constraints);
  }
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Typ.$$package(loc$1, attrs, modTypePath, /* [] */0);
}

function parseConstrainedModExpr(p) {
  var modExpr = parseModuleExpr(p);
  var match = p.token;
  if (match !== 24) {
    return modExpr;
  }
  Res_parser.next(undefined, p);
  var modType = parseModuleType(undefined, undefined, p);
  var loc_loc_start = modExpr.pmod_loc.loc_start;
  var loc_loc_end = modType.pmty_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Mod.constraint_(loc, undefined, modExpr, modType);
}

function parsePolymorphicVariantTypeArgs(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var args = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
  Res_parser.expect(undefined, /* Rparen */19, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  if (args) {
    var typ = args.hd;
    var tmp = typ.ptyp_desc;
    if (typeof tmp === "number") {
      if (!args.tl) {
        return typ;
      }
      
    } else if (tmp.TAG === /* Ptyp_tuple */2) {
      if (!args.tl) {
        if (p.mode === /* ParseForTypeChecker */0) {
          return typ;
        } else {
          return Ast_helper.Typ.tuple(loc, /* [] */0, args);
        }
      }
      
    } else if (!args.tl) {
      return typ;
    }
    
  }
  return Ast_helper.Typ.tuple(loc, /* [] */0, args);
}

function parsePolymorphicVariantTypeSpecHash(attrs, full, p) {
  var startPos = p.startPos;
  var match = parseHashIdent(startPos, p);
  var loop = function (p) {
    var match = p.token;
    if (match !== 69) {
      return /* [] */0;
    }
    if (!full) {
      return /* [] */0;
    }
    Res_parser.next(undefined, p);
    var rowField = parsePolymorphicVariantTypeArgs(p);
    return {
            hd: rowField,
            tl: loop(p)
          };
  };
  var match$1 = p.token;
  var match$2 = typeof match$1 === "number" ? (
      match$1 !== 18 ? (
          match$1 !== 69 || !full ? [
              /* [] */0,
              true
            ] : (Res_parser.next(undefined, p), [
                {
                  hd: parsePolymorphicVariantTypeArgs(p),
                  tl: /* [] */0
                },
                true
              ])
        ) : [
          {
            hd: parsePolymorphicVariantTypeArgs(p),
            tl: /* [] */0
          },
          false
        ]
    ) : [
      /* [] */0,
      true
    ];
  var tuples = Pervasives.$at(match$2[0], loop(p));
  return {
          TAG: /* Rtag */0,
          _0: $$Location.mkloc(match[0], match[1]),
          _1: attrs,
          _2: match$2[1],
          _3: tuples
        };
}

function parseTypExprRegion(p) {
  if (Res_grammar.isTypExprStart(p.token)) {
    return parseTypExpr(undefined, undefined, undefined, p);
  }
  
}

function parseModuleBindingBody(p) {
  var match = p.token;
  var returnModType = match === 24 ? (Res_parser.next(undefined, p), parseModuleType(undefined, undefined, p)) : undefined;
  Res_parser.expect(undefined, /* Equal */14, p);
  var modExpr = parseModuleExpr(p);
  if (returnModType !== undefined) {
    return Ast_helper.Mod.constraint_({
                loc_start: returnModType.pmty_loc.loc_start,
                loc_end: modExpr.pmod_loc.loc_end,
                loc_ghost: false
              }, undefined, modExpr, returnModType);
  } else {
    return modExpr;
  }
}

function parsePrimaryExpr(operand, noCallOpt, p) {
  var noCall = noCallOpt !== undefined ? noCallOpt : false;
  var startPos = operand.pexp_loc.loc_start;
  var _expr = operand;
  while(true) {
    var expr = _expr;
    var match = p.token;
    if (typeof match !== "number") {
      return expr;
    }
    if (match !== 4) {
      if (match >= 21) {
        if (match !== 80) {
          return expr;
        }
        if (!(noCall === false && p.prevEndPos.pos_lnum === p.startPos.pos_lnum)) {
          return expr;
        }
        var match$1 = expr.pexp_desc;
        if (typeof match$1 !== "number" && match$1.TAG === /* Pexp_ident */0) {
          var ident = match$1._0.txt;
          switch (ident.TAG | 0) {
            case /* Lident */0 :
                return parseTemplateExpr(ident._0, p);
            case /* Ldot */1 :
            case /* Lapply */2 :
                break;
            
          }
        }
        Res_parser.err(expr.pexp_loc.loc_start, expr.pexp_loc.loc_end, p, Res_diagnostics.message("Tagged template literals are currently restricted to names like: json`null`."));
        return parseTemplateExpr(undefined, p);
      }
      if (match < 18) {
        return expr;
      }
      switch (match) {
        case /* Lparen */18 :
            if (!(noCall === false && p.prevEndPos.pos_lnum === p.startPos.pos_lnum)) {
              return expr;
            }
            _expr = parseCallExpr(p, expr);
            continue ;
        case /* Rparen */19 :
            return expr;
        case /* Lbracket */20 :
            if (noCall === false && p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
              return parseBracketAccess(p, expr, startPos);
            } else {
              return expr;
            }
        
      }
    } else {
      Res_parser.next(undefined, p);
      var lident = parseValuePathAfterDot(p);
      var match$2 = p.token;
      if (match$2 === 14 && noCall === false) {
        Res_parser.leaveBreadcrumb(p, /* ExprSetField */9);
        Res_parser.next(undefined, p);
        var targetExpr = parseExpr(undefined, p);
        var loc_loc_end = p.prevEndPos;
        var loc = {
          loc_start: startPos,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        var setfield = Ast_helper.Exp.setfield(loc, undefined, expr, lident, targetExpr);
        Res_parser.eatBreadcrumb(p);
        return setfield;
      }
      var endPos = p.prevEndPos;
      var loc$1 = {
        loc_start: startPos,
        loc_end: endPos,
        loc_ghost: false
      };
      _expr = Ast_helper.Exp.field(loc$1, undefined, expr, lident);
      continue ;
    }
  };
}

function parseExceptionDef(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Exception */27, p);
  var match = parseConstrDef(false, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Te.constructor(loc, attrs, undefined, undefined, match[1], match[2]);
}

function parseNewlineOrSemicolonExprBlock(p) {
  var token = p.token;
  if (token === 8) {
    return Res_parser.next(undefined, p);
  } else if (Res_grammar.isBlockExprStart(token) && p.prevEndPos.pos_lnum >= p.startPos.pos_lnum) {
    return Res_parser.err(p.prevEndPos, p.endPos, p, Res_diagnostics.message("consecutive expressions on a line must be separated by ';' or a newline"));
  } else {
    return ;
  }
}

function parseLetBindings(attrs, p) {
  var startPos = p.startPos;
  Res_parser.optional(p, /* Let */9);
  var recFlag = Res_parser.optional(p, /* Rec */11) ? /* Recursive */1 : /* Nonrecursive */0;
  var first = parseLetBindingBody(startPos, attrs, p);
  var loop = function (p, _bindings) {
    while(true) {
      var bindings = _bindings;
      var startPos = p.startPos;
      var attrs = parseAttributesAndBinding(p);
      var match = p.token;
      if (match !== 10) {
        return List.rev(bindings);
      }
      Res_parser.next(undefined, p);
      var match$1 = p.token;
      var attrs$1;
      if (typeof match$1 === "number" && match$1 >= 84) {
        var exportLoc_loc_start = p.startPos;
        var exportLoc_loc_end = p.endPos;
        var exportLoc = {
          loc_start: exportLoc_loc_start,
          loc_end: exportLoc_loc_end,
          loc_ghost: false
        };
        Res_parser.next(undefined, p);
        var genTypeAttr_0 = $$Location.mkloc("genType", exportLoc);
        var genTypeAttr_1 = {
          TAG: /* PStr */0,
          _0: /* [] */0
        };
        var genTypeAttr = [
          genTypeAttr_0,
          genTypeAttr_1
        ];
        attrs$1 = {
          hd: genTypeAttr,
          tl: attrs
        };
      } else {
        attrs$1 = attrs;
      }
      Res_parser.optional(p, /* Let */9);
      var letBinding = parseLetBindingBody(startPos, attrs$1, p);
      _bindings = {
        hd: letBinding,
        tl: bindings
      };
      continue ;
    };
  };
  return [
          recFlag,
          loop(p, {
                hd: first,
                tl: /* [] */0
              })
        ];
}

function parseTernaryExpr(leftOperand, p) {
  var match = p.token;
  if (match !== 49) {
    return leftOperand;
  }
  Res_parser.leaveBreadcrumb(p, /* Ternary */2);
  Res_parser.next(undefined, p);
  var trueBranch = parseExpr(/* TernaryTrueBranchExpr */1, p);
  Res_parser.expect(undefined, /* Colon */24, p);
  var falseBranch = parseExpr(undefined, p);
  Res_parser.eatBreadcrumb(p);
  var init = leftOperand.pexp_loc;
  var loc_loc_start = leftOperand.pexp_loc.loc_start;
  var loc_loc_end = falseBranch.pexp_loc.loc_end;
  var loc_loc_ghost = init.loc_ghost;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: loc_loc_ghost
  };
  return Ast_helper.Exp.ifthenelse(loc, {
              hd: ternaryAttr,
              tl: /* [] */0
            }, leftOperand, trueBranch, falseBranch);
}

function parseFirstClassModuleExpr(startPos, p) {
  Res_parser.expect(undefined, /* Lparen */18, p);
  var modExpr = parseModuleExpr(p);
  var modEndLoc = p.prevEndPos;
  var match = p.token;
  if (match === 24) {
    var colonStart = p.startPos;
    Res_parser.next(undefined, p);
    var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
    var packageType = parsePackageType(colonStart, attrs, p);
    Res_parser.expect(undefined, /* Rparen */19, p);
    var loc = {
      loc_start: startPos,
      loc_end: modEndLoc,
      loc_ghost: false
    };
    var firstClassModule = Ast_helper.Exp.pack(loc, undefined, modExpr);
    var loc_loc_end = p.prevEndPos;
    var loc$1 = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return Ast_helper.Exp.constraint_(loc$1, undefined, firstClassModule, packageType);
  }
  Res_parser.expect(undefined, /* Rparen */19, p);
  var loc_loc_end$1 = p.prevEndPos;
  var loc$2 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Exp.pack(loc$2, undefined, modExpr);
}

function parseBinaryExpr(contextOpt, a, p, prec) {
  var context = contextOpt !== undefined ? contextOpt : /* OrdinaryExpr */0;
  var a$1 = a !== undefined ? a : parseOperandExpr(context, p);
  var _a = a$1;
  while(true) {
    var a$2 = _a;
    var token = p.token;
    var tokenPrec;
    var exit = 0;
    if (typeof token === "number") {
      if (token >= 36) {
        if (token !== 42) {
          tokenPrec = Res_token.precedence(token);
        } else {
          exit = 1;
        }
      } else if (token >= 34) {
        exit = 1;
      } else {
        tokenPrec = Res_token.precedence(token);
      }
    } else {
      tokenPrec = Res_token.precedence(token);
    }
    if (exit === 1) {
      tokenPrec = !Res_scanner.isBinaryOp(p.scanner.src, p.startPos.pos_cnum, p.endPos.pos_cnum) && p.startPos.pos_lnum > p.prevEndPos.pos_lnum ? -1 : Res_token.precedence(token);
    }
    if (tokenPrec < prec) {
      return a$2;
    }
    Res_parser.leaveBreadcrumb(p, /* ExprBinaryAfterOp */{
          _0: token
        });
    var startPos = p.startPos;
    Res_parser.next(undefined, p);
    var endPos = p.prevEndPos;
    var b = parseBinaryExpr(context, undefined, p, tokenPrec + 1 | 0);
    var loc_loc_start = a$2.pexp_loc.loc_start;
    var loc_loc_end = b.pexp_loc.loc_end;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    var expr = Ast_helper.Exp.apply(loc, undefined, makeInfixOperator(p, token, startPos, endPos), {
          hd: [
            /* Nolabel */0,
            a$2
          ],
          tl: {
            hd: [
              /* Nolabel */0,
              b
            ],
            tl: /* [] */0
          }
        });
    Res_parser.eatBreadcrumb(p);
    _a = expr;
    continue ;
  };
}

function parseOperandExpr(context, p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  var expr;
  var exit = 0;
  if (typeof match === "number") {
    if (match >= 56) {
      if (match !== 82) {
        exit = 1;
      } else {
        expr = parseTryExpression(p);
      }
    } else if (match >= 46) {
      switch (match) {
        case /* Assert */46 :
            Res_parser.next(undefined, p);
            var expr$1 = parseUnaryExpr(p);
            var loc_loc_end = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            expr = Ast_helper.Exp.assert_(loc, undefined, expr$1);
            break;
        case /* Lazy */47 :
            Res_parser.next(undefined, p);
            var expr$2 = parseUnaryExpr(p);
            var loc_loc_end$1 = p.prevEndPos;
            var loc$1 = {
              loc_start: startPos,
              loc_end: loc_loc_end$1,
              loc_ghost: false
            };
            expr = Ast_helper.Exp.lazy_(loc$1, undefined, expr$2);
            break;
        case /* If */50 :
            expr = parseIfOrIfLetExpression(p);
            break;
        case /* For */52 :
            expr = parseForExpression(p);
            break;
        case /* Tilde */48 :
        case /* Question */49 :
        case /* Else */51 :
        case /* In */53 :
            exit = 1;
            break;
        case /* While */54 :
            expr = parseWhileExpression(p);
            break;
        case /* Switch */55 :
            expr = parseSwitchExpression(p);
            break;
        
      }
    } else {
      exit = 1;
    }
  } else {
    exit = 1;
  }
  if (exit === 1) {
    expr = context !== /* WhenExpr */2 && isEs6ArrowExpression(context === /* TernaryTrueBranchExpr */1, p) ? parseEs6ArrowExpression(context, undefined, p) : parseUnaryExpr(p);
  }
  return {
          pexp_desc: expr.pexp_desc,
          pexp_loc: expr.pexp_loc,
          pexp_attributes: List.concat({
                hd: expr.pexp_attributes,
                tl: {
                  hd: attrs,
                  tl: /* [] */0
                }
              })
        };
}

function parseStandaloneAttribute(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* AtAt */76, p);
  var attrId = parseAttributeId(startPos, p);
  var payload = parsePayload(p);
  return [
          attrId,
          payload
        ];
}

function parseJsExport(attrs, p) {
  var exportStart = p.startPos;
  Res_parser.expect(undefined, /* Export */84, p);
  var exportLoc_loc_end = p.prevEndPos;
  var exportLoc = {
    loc_start: exportStart,
    loc_end: exportLoc_loc_end,
    loc_ghost: false
  };
  var genTypeAttr_0 = $$Location.mkloc("genType", exportLoc);
  var genTypeAttr_1 = {
    TAG: /* PStr */0,
    _0: /* [] */0
  };
  var genTypeAttr = [
    genTypeAttr_0,
    genTypeAttr_1
  ];
  var attrs$1 = {
    hd: genTypeAttr,
    tl: attrs
  };
  var match = p.token;
  if (match === 60) {
    var ext = parseTypeDefinitionOrExtension(attrs$1, p);
    if (ext.TAG === /* TypeDef */0) {
      return Ast_helper.Str.type_(undefined, ext.recFlag, ext.types);
    } else {
      return Ast_helper.Str.type_extension(undefined, ext._0);
    }
  }
  var match$1 = parseLetBindings(attrs$1, p);
  return Ast_helper.Str.value(undefined, match$1[0], match$1[1]);
}

function parseModuleOrModuleTypeImplOrPackExpr(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Module */65, p);
  var match = p.token;
  if (typeof match !== "number") {
    return parseMaybeRecModuleBinding(attrs, startPos, p);
  }
  if (match !== 18) {
    if (match !== 60) {
      return parseMaybeRecModuleBinding(attrs, startPos, p);
    } else {
      return parseModuleTypeImpl(attrs, startPos, p);
    }
  }
  var expr = parseFirstClassModuleExpr(startPos, p);
  var a = parsePrimaryExpr(expr, undefined, p);
  var expr$1 = parseBinaryExpr(undefined, a, p, 1);
  var expr$2 = parseTernaryExpr(expr$1, p);
  return Ast_helper.Str.$$eval(undefined, attrs, expr$2);
}

function parseExternalDef(attrs, startPos, p) {
  Res_parser.leaveBreadcrumb(p, /* External */21);
  Res_parser.expect(undefined, /* External */59, p);
  var match = parseLident(p);
  var name = $$Location.mkloc(match[0], match[1]);
  Res_parser.expect(/* TypeExpression */20, /* Colon */24, p);
  var typExpr = parseTypExpr(undefined, undefined, undefined, p);
  var equalStart = p.startPos;
  var equalEnd = p.endPos;
  Res_parser.expect(undefined, /* Equal */14, p);
  var s = p.token;
  var prim;
  var exit = 0;
  if (typeof s === "number" || s.TAG !== /* String */3) {
    exit = 1;
  } else {
    Res_parser.next(undefined, p);
    prim = {
      hd: s._0,
      tl: /* [] */0
    };
  }
  if (exit === 1) {
    Res_parser.err(equalStart, equalEnd, p, Res_diagnostics.message("An external requires the name of the JS value you're referring to, like \"" + (name.txt + "\".")));
    prim = /* [] */0;
  }
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var vb = Ast_helper.Val.mk(loc, attrs, undefined, prim, name, typExpr);
  Res_parser.eatBreadcrumb(p);
  return vb;
}

function parseNewlineOrSemicolonStructure(p) {
  var token = p.token;
  if (token === 8) {
    return Res_parser.next(undefined, p);
  } else if (Res_grammar.isStructureItemStart(token) && p.prevEndPos.pos_lnum >= p.startPos.pos_lnum) {
    return Res_parser.err(p.prevEndPos, p.endPos, p, Res_diagnostics.message("consecutive statements on a line must be separated by ';' or a newline"));
  } else {
    return ;
  }
}

function parseTypeDefinitionOrExtension(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Typ */60, p);
  var match = p.token;
  var recFlag;
  if (typeof match === "number") {
    if (match === /* Rec */11) {
      Res_parser.next(undefined, p);
      recFlag = /* Recursive */1;
    } else {
      recFlag = /* Nonrecursive */0;
    }
  } else if (match.TAG === /* Lident */4 && match._0 === "nonrec") {
    Res_parser.next(undefined, p);
    recFlag = /* Nonrecursive */0;
  } else {
    recFlag = /* Nonrecursive */0;
  }
  var name = parseValuePath(p);
  var params = parseTypeParams(name, p);
  var match$1 = p.token;
  if (match$1 === 39) {
    return {
            TAG: /* TypeExt */1,
            _0: parseTypeExtension(params, attrs, name, p)
          };
  }
  var longident = name.txt;
  var exit = 0;
  switch (longident.TAG | 0) {
    case /* Lident */0 :
        break;
    case /* Ldot */1 :
    case /* Lapply */2 :
        exit = 1;
        break;
    
  }
  if (exit === 1) {
    Res_parser.err(name.loc.loc_start, name.loc.loc_end, p, Res_diagnostics.message(typeDeclarationNameLongident(longident)));
  }
  var typeDefs = parseTypeDefinitions(attrs, name, params, startPos, p);
  return {
          TAG: /* TypeDef */0,
          recFlag: recFlag,
          types: typeDefs
        };
}

function parseExtension(moduleLanguageOpt, p) {
  var moduleLanguage = moduleLanguageOpt !== undefined ? moduleLanguageOpt : false;
  var startPos = p.startPos;
  if (moduleLanguage) {
    Res_parser.expect(undefined, /* PercentPercent */78, p);
  } else {
    Res_parser.expect(undefined, /* Percent */77, p);
  }
  var attrId = parseAttributeId(startPos, p);
  var payload = parsePayload(p);
  return [
          attrId,
          payload
        ];
}

function parseIncludeStatement(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Include */64, p);
  var modExpr = parseModuleExpr(p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Incl.mk(loc, attrs, undefined, modExpr);
}

function parseJsImport(startPos, attrs, p) {
  Res_parser.expect(undefined, /* Import */83, p);
  var match = p.token;
  var importSpec;
  var exit = 0;
  if (typeof match === "number") {
    if (match === /* At */75) {
      exit = 1;
    } else {
      importSpec = {
        TAG: /* Spec */1,
        _0: parseJsFfiDeclarations(p)
      };
    }
  } else if (match.TAG === /* Lident */4) {
    exit = 1;
  } else {
    importSpec = {
      TAG: /* Spec */1,
      _0: parseJsFfiDeclarations(p)
    };
  }
  if (exit === 1) {
    var decl = parseJsFfiDeclaration(p);
    var decl$1;
    if (decl !== undefined) {
      decl$1 = decl;
    } else {
      throw {
            RE_EXN_ID: "Assert_failure",
            _1: [
              "res_core.res",
              6159,
              14
            ],
            Error: new Error()
          };
    }
    importSpec = {
      TAG: /* Default */0,
      _0: decl$1
    };
  }
  var scope = parseJsFfiScope(p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Res_js_ffi.importDescr(attrs, scope, importSpec, loc);
}

function parseRecordPatternField(p) {
  var label = parseValuePath(p);
  var match = p.token;
  var pattern = match === 24 ? (Res_parser.next(undefined, p), parsePattern(undefined, undefined, p)) : Ast_helper.Pat.$$var(label.loc, undefined, $$Location.mkloc(Longident.last(label.txt), label.loc));
  return [
          label,
          pattern
        ];
}

function parseTypeParam(p) {
  var match = p.token;
  var variance;
  if (typeof match === "number") {
    switch (match) {
      case /* Minus */34 :
          Res_parser.next(undefined, p);
          variance = /* Contravariant */1;
          break;
      case /* MinusDot */35 :
          variance = /* Invariant */2;
          break;
      case /* Plus */36 :
          Res_parser.next(undefined, p);
          variance = /* Covariant */0;
          break;
      default:
        variance = /* Invariant */2;
    }
  } else {
    variance = /* Invariant */2;
  }
  var token = p.token;
  if (typeof token === "number") {
    switch (token) {
      case /* Underscore */12 :
          var loc_loc_start = p.startPos;
          var loc_loc_end = p.endPos;
          var loc = {
            loc_start: loc_loc_start,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          Res_parser.next(undefined, p);
          return [
                  Ast_helper.Typ.any(loc, undefined, undefined),
                  variance
                ];
      case /* SingleQuote */13 :
          Res_parser.next(undefined, p);
          var match$1 = parseIdent(typeParam, p.startPos, p);
          return [
                  Ast_helper.Typ.$$var(match$1[1], undefined, match$1[0]),
                  variance
                ];
      default:
        return ;
    }
  } else {
    switch (token.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          break;
      default:
        return ;
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.message("Type params start with a singlequote: '" + Res_token.toString(token)));
  var match$2 = parseIdent(typeParam, p.startPos, p);
  return [
          Ast_helper.Typ.$$var(match$2[1], undefined, match$2[0]),
          variance
        ];
}

function parseTypeConstructorArgs(constrName, p) {
  var opening = p.token;
  var openingStartPos = p.startPos;
  if (typeof opening !== "number") {
    return /* [] */0;
  }
  if (opening !== 18 && opening !== 42) {
    return /* [] */0;
  }
  Res_scanner.setDiamondMode(p.scanner);
  Res_parser.next(undefined, p);
  var typeArgs = parseCommaDelimitedRegion(p, /* TypExprList */39, /* GreaterThan */41, parseTypeConstructorArgRegion);
  var match = p.token;
  if (match === 19 && opening === /* Lparen */18) {
    var typ = Ast_helper.Typ.constr(undefined, undefined, constrName, typeArgs);
    var msg = Res_doc.toString(80, Res_doc.breakableGroup(true, Res_doc.concat({
                  hd: Res_doc.text("Type parameters require angle brackets:"),
                  tl: {
                    hd: Res_doc.indent(Res_doc.concat({
                              hd: Res_doc.line,
                              tl: {
                                hd: Res_printer.printTypExpr(typ, Res_comments_table.empty),
                                tl: /* [] */0
                              }
                            })),
                    tl: /* [] */0
                  }
                })));
    Res_parser.err(openingStartPos, undefined, p, Res_diagnostics.message(msg));
    Res_parser.next(undefined, p);
  } else {
    Res_parser.expect(undefined, /* GreaterThan */41, p);
  }
  Res_scanner.popMode(p.scanner, /* Diamond */1);
  return typeArgs;
}

function parseTypeRepresentation(p) {
  Res_parser.leaveBreadcrumb(p, /* TypeRepresentation */33);
  var privateFlag = Res_parser.optional(p, /* Private */61) ? /* Private */0 : /* Public */1;
  var token = p.token;
  var kind;
  var exit = 0;
  if (typeof token === "number") {
    switch (token) {
      case /* DotDot */5 :
          Res_parser.next(undefined, p);
          kind = /* Ptype_open */1;
          break;
      case /* Bar */17 :
          kind = {
            TAG: /* Ptype_variant */0,
            _0: parseTypeConstructorDeclarations(undefined, p)
          };
          break;
      case /* Lbrace */22 :
          kind = {
            TAG: /* Ptype_record */1,
            _0: parseRecordDeclaration(p)
          };
          break;
      default:
        exit = 1;
    }
  } else if (token.TAG === /* Uident */5) {
    kind = {
      TAG: /* Ptype_variant */0,
      _0: parseTypeConstructorDeclarations(undefined, p)
    };
  } else {
    exit = 1;
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
    kind = {
      TAG: /* Ptype_variant */0,
      _0: /* [] */0
    };
  }
  Res_parser.eatBreadcrumb(p);
  return [
          privateFlag,
          kind
        ];
}

function parseTypeConstructorDeclarations(first, p) {
  var firstConstrDecl;
  if (first !== undefined) {
    firstConstrDecl = first;
  } else {
    var startPos = p.startPos;
    Res_parser.optional(p, /* Bar */17);
    firstConstrDecl = parseTypeConstructorDeclaration(startPos, p);
  }
  return {
          hd: firstConstrDecl,
          tl: parseRegion(p, /* ConstructorDeclaration */35, parseTypeConstructorDeclarationWithBar)
        };
}

function parseParameterList(p) {
  var parameters = parseCommaDelimitedRegion(p, /* ParameterList */36, /* Rparen */19, parseParameter);
  Res_parser.expect(undefined, /* Rparen */19, p);
  return parameters;
}

function parseTypeConstraint(p) {
  var startPos = p.startPos;
  var match = p.token;
  if (match !== 63) {
    return ;
  }
  Res_parser.next(undefined, p);
  Res_parser.expect(undefined, /* SingleQuote */13, p);
  var ident = p.token;
  if (typeof ident !== "number" && ident.TAG === /* Lident */4) {
    var identLoc_loc_end = p.endPos;
    var identLoc = {
      loc_start: startPos,
      loc_end: identLoc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    Res_parser.expect(undefined, /* Equal */14, p);
    var typ = parseTypExpr(undefined, undefined, undefined, p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return [
            Ast_helper.Typ.$$var(identLoc, undefined, ident._0),
            typ,
            loc
          ];
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.lident(ident));
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return [
          Ast_helper.Typ.any(undefined, undefined, undefined),
          parseTypExpr(undefined, undefined, undefined, p),
          loc$1
        ];
}

function parseAttributesAndBinding(p) {
  var err = p.scanner.err;
  var ch = p.scanner.ch;
  var offset = p.scanner.offset;
  var lineOffset = p.scanner.lineOffset;
  var lnum = p.scanner.lnum;
  var mode = p.scanner.mode;
  var token = p.token;
  var startPos = p.startPos;
  var endPos = p.endPos;
  var prevEndPos = p.prevEndPos;
  var breadcrumbs = p.breadcrumbs;
  var errors = p.errors;
  var diagnostics = p.diagnostics;
  var comments = p.comments;
  var match = p.token;
  if (match !== 75) {
    return /* [] */0;
  }
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match$1 = p.token;
  if (match$1 === 10) {
    return attrs;
  } else {
    p.scanner.err = err;
    p.scanner.ch = ch;
    p.scanner.offset = offset;
    p.scanner.lineOffset = lineOffset;
    p.scanner.lnum = lnum;
    p.scanner.mode = mode;
    p.token = token;
    p.startPos = startPos;
    p.endPos = endPos;
    p.prevEndPos = prevEndPos;
    p.breadcrumbs = breadcrumbs;
    p.errors = errors;
    p.diagnostics = diagnostics;
    p.comments = comments;
    return /* [] */0;
  }
}

function parseTypeDef(attrs, startPos, p) {
  Res_parser.leaveBreadcrumb(p, /* TypeDef */28);
  Res_parser.leaveBreadcrumb(p, /* TypeConstrName */29);
  var match = parseLident(p);
  var loc = match[1];
  var name = match[0];
  var typeConstrName = $$Location.mkloc(name, loc);
  Res_parser.eatBreadcrumb(p);
  var constrName = $$Location.mkloc({
        TAG: /* Lident */0,
        _0: name
      }, loc);
  var params = parseTypeParams(constrName, p);
  var match$1 = parseTypeEquationAndRepresentation(p);
  var cstrs = parseRegion(p, /* TypeConstraint */51, parseTypeConstraint);
  var loc_loc_end = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var typeDef = Ast_helper.Type.mk(loc$1, attrs, undefined, undefined, params, cstrs, match$1[2], match$1[1], match$1[0], typeConstrName);
  Res_parser.eatBreadcrumb(p);
  return typeDef;
}

function parseTypeEquationAndRepresentation(p) {
  var token = p.token;
  var exit = 0;
  if (typeof token !== "number") {
    return [
            undefined,
            /* Public */1,
            /* Ptype_abstract */0
          ];
  }
  if (token !== 14) {
    if (token !== 17) {
      return [
              undefined,
              /* Public */1,
              /* Ptype_abstract */0
            ];
    }
    exit = 1;
  } else {
    exit = 1;
  }
  if (exit === 1) {
    if (token === /* Bar */17) {
      Res_parser.expect(undefined, /* Equal */14, p);
    }
    Res_parser.next(undefined, p);
    var match = p.token;
    var exit$1 = 0;
    if (typeof match === "number") {
      switch (match) {
        case /* DotDot */5 :
        case /* Bar */17 :
            exit$1 = 3;
            break;
        case /* Lbrace */22 :
            return parseRecordOrObjectDecl(p);
        case /* Private */61 :
            return parsePrivateEqOrRepr(p);
        default:
          exit$1 = 2;
      }
    } else {
      if (match.TAG === /* Uident */5) {
        return parseTypeEquationOrConstrDecl(p);
      }
      exit$1 = 2;
    }
    switch (exit$1) {
      case 2 :
          var manifest = parseTypExpr(undefined, undefined, undefined, p);
          var match$1 = p.token;
          if (match$1 !== 14) {
            return [
                    manifest,
                    /* Public */1,
                    /* Ptype_abstract */0
                  ];
          }
          Res_parser.next(undefined, p);
          var match$2 = parseTypeRepresentation(p);
          return [
                  manifest,
                  match$2[0],
                  match$2[1]
                ];
      case 3 :
          var match$3 = parseTypeRepresentation(p);
          return [
                  undefined,
                  match$3[0],
                  match$3[1]
                ];
      
    }
  }
  
}

function parseIfLetExpr(startPos, p) {
  var pattern = parsePattern(undefined, undefined, p);
  Res_parser.expect(undefined, /* Equal */14, p);
  var conditionExpr = parseIfCondition(p);
  var thenExpr = parseThenBranch(p);
  var match = p.token;
  var elseExpr;
  Res_parser.endRegion(p);
  if (match === 51) {
    Res_parser.leaveBreadcrumb(p, /* ElseBranch */19);
    Res_parser.next(undefined, p);
    Res_parser.beginRegion(p);
    var match$1 = p.token;
    var elseExpr$1 = match$1 === 50 ? parseIfOrIfLetExpression(p) : parseElseBranch(p);
    Res_parser.eatBreadcrumb(p);
    Res_parser.endRegion(p);
    elseExpr = elseExpr$1;
  } else {
    var startPos$1 = p.startPos;
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos$1,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    elseExpr = Ast_helper.Exp.construct(loc, undefined, $$Location.mkloc({
              TAG: /* Lident */0,
              _0: "()"
            }, loc), undefined);
  }
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Exp.match_(loc$1, {
              hd: ifLetAttr,
              tl: {
                hd: suppressFragileMatchWarningAttr,
                tl: /* [] */0
              }
            }, conditionExpr, {
              hd: Ast_helper.Exp.$$case(pattern, undefined, thenExpr),
              tl: {
                hd: Ast_helper.Exp.$$case(Ast_helper.Pat.any(undefined, undefined, undefined), undefined, elseExpr),
                tl: /* [] */0
              }
            });
}

function parseIfExpr(startPos, p) {
  var conditionExpr = parseIfCondition(p);
  var thenExpr = parseThenBranch(p);
  var match = p.token;
  var elseExpr;
  Res_parser.endRegion(p);
  if (match === 51) {
    Res_parser.leaveBreadcrumb(p, /* ElseBranch */19);
    Res_parser.next(undefined, p);
    Res_parser.beginRegion(p);
    var match$1 = p.token;
    var elseExpr$1 = match$1 === 50 ? parseIfOrIfLetExpression(p) : parseElseBranch(p);
    Res_parser.eatBreadcrumb(p);
    Res_parser.endRegion(p);
    elseExpr = elseExpr$1;
  } else {
    elseExpr = undefined;
  }
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.ifthenelse(loc, undefined, conditionExpr, thenExpr, elseExpr);
}

function parseRecordOrObjectDecl(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var match = p.token;
  var exit = 0;
  if (typeof match === "number") {
    if (match >= 6) {
      if (match >= 7) {
        exit = 1;
      } else {
        var dotdotdotStart = p.startPos;
        var dotdotdotEnd = p.endPos;
        Res_parser.next(undefined, p);
        var typ = parseTypExpr(undefined, undefined, undefined, p);
        var match$1 = p.token;
        if (match$1 === 23) {
          Res_parser.err(dotdotdotStart, dotdotdotEnd, p, Res_diagnostics.message(sameTypeSpread));
          Res_parser.next(undefined, p);
        } else {
          Res_parser.expect(undefined, /* Comma */25, p);
        }
        var match$2 = p.token;
        if (typeof match$2 !== "number" && match$2.TAG === /* Lident */4) {
          Res_parser.err(dotdotdotStart, dotdotdotEnd, p, Res_diagnostics.message(spreadInRecordDeclaration));
        }
        var fields_0 = {
          TAG: /* Oinherit */1,
          _0: typ
        };
        var fields_1 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
        var fields = {
          hd: fields_0,
          tl: fields_1
        };
        Res_parser.expect(undefined, /* Rbrace */23, p);
        var loc_loc_end = p.prevEndPos;
        var loc = {
          loc_start: startPos,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        var typ$1 = parseTypeAlias(p, Ast_helper.Typ.object_(loc, undefined, fields, /* Closed */0));
        var typ$2 = parseArrowTypeRest(true, startPos, typ$1, p);
        return [
                typ$2,
                /* Public */1,
                /* Ptype_abstract */0
              ];
      }
    } else {
      if (match >= 4) {
        var match$3 = p.token;
        var closedFlag = typeof match$3 === "number" ? (
            match$3 !== 4 ? (
                match$3 !== 5 ? /* Closed */0 : (Res_parser.next(undefined, p), /* Open */1)
              ) : (Res_parser.next(undefined, p), /* Closed */0)
          ) : /* Closed */0;
        var fields$1 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
        Res_parser.expect(undefined, /* Rbrace */23, p);
        var loc_loc_end$1 = p.prevEndPos;
        var loc$1 = {
          loc_start: startPos,
          loc_end: loc_loc_end$1,
          loc_ghost: false
        };
        var typ$3 = parseTypeAlias(p, Ast_helper.Typ.object_(loc$1, /* [] */0, fields$1, closedFlag));
        var typ$4 = parseArrowTypeRest(true, startPos, typ$3, p);
        return [
                typ$4,
                /* Public */1,
                /* Ptype_abstract */0
              ];
      }
      exit = 1;
    }
  } else {
    exit = 1;
  }
  if (exit === 1) {
    var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
    var match$4 = p.token;
    var exit$1 = 0;
    if (typeof match$4 === "number") {
      exit$1 = 2;
    } else {
      if (match$4.TAG === /* String */3) {
        var fields$2;
        if (attrs) {
          Res_parser.leaveBreadcrumb(p, /* StringFieldDeclarations */37);
          var field = parseStringFieldDeclaration(p);
          var field$1;
          if (field !== undefined) {
            field$1 = field;
          } else {
            throw {
                  RE_EXN_ID: "Assert_failure",
                  _1: [
                    "res_core.res",
                    5486,
                    20
                  ],
                  Error: new Error()
                };
          }
          var match$5 = p.token;
          if (typeof match$5 === "number") {
            if (match$5 >= 24) {
              if (match$5 >= 27) {
                Res_parser.expect(undefined, /* Comma */25, p);
              } else {
                switch (match$5) {
                  case /* Colon */24 :
                      Res_parser.expect(undefined, /* Comma */25, p);
                      break;
                  case /* Comma */25 :
                      Res_parser.next(undefined, p);
                      break;
                  case /* Eof */26 :
                      break;
                  
                }
              }
            } else if (match$5 >= 23) {
              
            } else {
              Res_parser.expect(undefined, /* Comma */25, p);
            }
          } else {
            Res_parser.expect(undefined, /* Comma */25, p);
          }
          Res_parser.eatBreadcrumb(p);
          var first;
          first = field$1.TAG === /* Otag */0 ? ({
                TAG: /* Otag */0,
                _0: field$1._0,
                _1: attrs,
                _2: field$1._2
              }) : ({
                TAG: /* Oinherit */1,
                _0: field$1._0
              });
          fields$2 = {
            hd: first,
            tl: parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration)
          };
        } else {
          fields$2 = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
        }
        Res_parser.expect(undefined, /* Rbrace */23, p);
        var loc_loc_end$2 = p.prevEndPos;
        var loc$2 = {
          loc_start: startPos,
          loc_end: loc_loc_end$2,
          loc_ghost: false
        };
        var typ$5 = parseTypeAlias(p, Ast_helper.Typ.object_(loc$2, /* [] */0, fields$2, /* Closed */0));
        var typ$6 = parseArrowTypeRest(true, startPos, typ$5, p);
        return [
                typ$6,
                /* Public */1,
                /* Ptype_abstract */0
              ];
      }
      exit$1 = 2;
    }
    if (exit$1 === 2) {
      Res_parser.leaveBreadcrumb(p, /* RecordDecl */34);
      var fields$3;
      if (attrs) {
        var field$2 = parseFieldDeclaration(p);
        Res_parser.optional(p, /* Comma */25);
        var init = field$2.pld_loc;
        var first_pld_name = field$2.pld_name;
        var first_pld_mutable = field$2.pld_mutable;
        var first_pld_type = field$2.pld_type;
        var first_pld_loc = {
          loc_start: attrs.hd[0].loc.loc_start,
          loc_end: init.loc_end,
          loc_ghost: init.loc_ghost
        };
        var first$1 = {
          pld_name: first_pld_name,
          pld_mutable: first_pld_mutable,
          pld_type: first_pld_type,
          pld_loc: first_pld_loc,
          pld_attributes: attrs
        };
        fields$3 = {
          hd: first$1,
          tl: parseCommaDelimitedRegion(p, /* FieldDeclarations */38, /* Rbrace */23, parseFieldDeclarationRegion)
        };
      } else {
        fields$3 = parseCommaDelimitedRegion(p, /* FieldDeclarations */38, /* Rbrace */23, parseFieldDeclarationRegion);
      }
      if (fields$3) {
        
      } else {
        Res_parser.err(startPos, undefined, p, Res_diagnostics.message("A record needs at least one field"));
      }
      Res_parser.expect(undefined, /* Rbrace */23, p);
      Res_parser.eatBreadcrumb(p);
      return [
              undefined,
              /* Public */1,
              {
                TAG: /* Ptype_record */1,
                _0: fields$3
              }
            ];
    }
    
  }
  
}

function parseTypeEquationOrConstrDecl(p) {
  var uidentStartPos = p.startPos;
  var uident = p.token;
  if (typeof uident !== "number" && uident.TAG === /* Uident */5) {
    var uident$1 = uident._0;
    Res_parser.next(undefined, p);
    var match = p.token;
    if (match === 4) {
      Res_parser.next(undefined, p);
      var typeConstr = parseValuePathTail(p, uidentStartPos, {
            TAG: /* Lident */0,
            _0: uident$1
          });
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: uidentStartPos,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      var typ = parseTypeAlias(p, Ast_helper.Typ.constr(loc, undefined, typeConstr, parseTypeConstructorArgs(typeConstr, p)));
      var match$1 = p.token;
      if (typeof match$1 !== "number") {
        return [
                typ,
                /* Public */1,
                /* Ptype_abstract */0
              ];
      }
      if (match$1 !== 14) {
        if (match$1 !== 57) {
          return [
                  typ,
                  /* Public */1,
                  /* Ptype_abstract */0
                ];
        }
        Res_parser.next(undefined, p);
        var returnType = parseTypExpr(undefined, undefined, false, p);
        var loc_loc_end$1 = p.prevEndPos;
        var loc$1 = {
          loc_start: uidentStartPos,
          loc_end: loc_loc_end$1,
          loc_ghost: false
        };
        var arrowType = Ast_helper.Typ.arrow(loc$1, undefined, /* Nolabel */0, typ, returnType);
        var typ$1 = parseTypeAlias(p, arrowType);
        return [
                typ$1,
                /* Public */1,
                /* Ptype_abstract */0
              ];
      }
      Res_parser.next(undefined, p);
      var match$2 = parseTypeRepresentation(p);
      return [
              typ,
              match$2[0],
              match$2[1]
            ];
    }
    var uidentEndPos = p.prevEndPos;
    var match$3 = parseConstrDeclArgs(p);
    var uidentLoc = {
      loc_start: uidentStartPos,
      loc_end: uidentEndPos,
      loc_ghost: false
    };
    var first = Ast_helper.Type.constructor({
          loc_start: uidentStartPos,
          loc_end: p.prevEndPos,
          loc_ghost: false
        }, undefined, undefined, match$3[0], match$3[1], $$Location.mkloc(uident$1, uidentLoc));
    return [
            undefined,
            /* Public */1,
            {
              TAG: /* Ptype_variant */0,
              _0: parseTypeConstructorDeclarations(first, p)
            }
          ];
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(uident));
  return [
          undefined,
          /* Public */1,
          /* Ptype_abstract */0
        ];
}

function parseJsFfiDeclaration(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (typeof match === "number") {
    return ;
  }
  if (match.TAG !== /* Lident */4) {
    return ;
  }
  var match$1 = parseLident(p);
  var ident = match$1[0];
  var match$2 = p.token;
  var alias = match$2 === 3 ? (Res_parser.next(undefined, p), parseLident(p)[0]) : ident;
  Res_parser.expect(undefined, /* Colon */24, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Res_js_ffi.decl(attrs, loc, ident, alias, typ);
}

function parseWithConstraint(p) {
  var token = p.token;
  if (typeof token === "number") {
    if (token !== 60) {
      if (token === 65) {
        Res_parser.next(undefined, p);
        var modulePath = parseModuleLongIdent(false, p);
        var token$1 = p.token;
        var exit = 0;
        if (typeof token$1 === "number") {
          if (token$1 !== 14) {
            if (token$1 !== 74) {
              exit = 2;
            } else {
              Res_parser.next(undefined, p);
              var lident = parseModuleLongIdent(false, p);
              return {
                      TAG: /* Pwith_modsubst */3,
                      _0: modulePath,
                      _1: lident
                    };
            }
          } else {
            Res_parser.next(undefined, p);
            var lident$1 = parseModuleLongIdent(false, p);
            return {
                    TAG: /* Pwith_module */1,
                    _0: modulePath,
                    _1: lident$1
                  };
          }
        } else {
          exit = 2;
        }
        if (exit === 2) {
          Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token$1, p.breadcrumbs));
          var lident$2 = parseModuleLongIdent(false, p);
          return {
                  TAG: /* Pwith_modsubst */3,
                  _0: modulePath,
                  _1: lident$2
                };
        }
        
      }
      
    } else {
      Res_parser.next(undefined, p);
      var typeConstr = parseValuePath(p);
      var params = parseTypeParams(typeConstr, p);
      var token$2 = p.token;
      var exit$1 = 0;
      if (typeof token$2 === "number") {
        if (token$2 !== 14) {
          if (token$2 !== 74) {
            exit$1 = 2;
          } else {
            Res_parser.next(undefined, p);
            var typExpr = parseTypExpr(undefined, undefined, undefined, p);
            return {
                    TAG: /* Pwith_typesubst */2,
                    _0: typeConstr,
                    _1: Ast_helper.Type.mk(typeConstr.loc, undefined, undefined, undefined, params, undefined, undefined, undefined, typExpr, $$Location.mkloc(Longident.last(typeConstr.txt), typeConstr.loc))
                  };
          }
        } else {
          Res_parser.next(undefined, p);
          var typExpr$1 = parseTypExpr(undefined, undefined, undefined, p);
          var typeConstraints = parseRegion(p, /* TypeConstraint */51, parseTypeConstraint);
          return {
                  TAG: /* Pwith_type */0,
                  _0: typeConstr,
                  _1: Ast_helper.Type.mk(typeConstr.loc, undefined, undefined, undefined, params, typeConstraints, undefined, undefined, typExpr$1, $$Location.mkloc(Longident.last(typeConstr.txt), typeConstr.loc))
                };
        }
      } else {
        exit$1 = 2;
      }
      if (exit$1 === 2) {
        Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token$2, p.breadcrumbs));
        var typExpr$2 = parseTypExpr(undefined, undefined, undefined, p);
        var typeConstraints$1 = parseRegion(p, /* TypeConstraint */51, parseTypeConstraint);
        return {
                TAG: /* Pwith_type */0,
                _0: typeConstr,
                _1: Ast_helper.Type.mk(typeConstr.loc, undefined, undefined, undefined, params, typeConstraints$1, undefined, undefined, typExpr$2, $$Location.mkloc(Longident.last(typeConstr.txt), typeConstr.loc))
              };
      }
      
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
  return {
          TAG: /* Pwith_type */0,
          _0: $$Location.mknoloc({
                TAG: /* Lident */0,
                _0: ""
              }),
          _1: Ast_helper.Type.mk(undefined, undefined, undefined, undefined, /* [] */0, /* [] */0, undefined, undefined, defaultType(undefined), $$Location.mknoloc(""))
        };
}

function parseTypeParameter(p) {
  if (!(p.token === /* Tilde */48 || p.token === /* Dot */4 || Res_grammar.isTypExprStart(p.token))) {
    return ;
  }
  var startPos = p.startPos;
  var uncurried = Res_parser.optional(p, /* Dot */4);
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (typeof match === "number") {
    if (match === /* Tilde */48) {
      Res_parser.next(undefined, p);
      var match$1 = parseLident(p);
      var name = match$1[0];
      var lblLocAttr_0 = $$Location.mkloc("ns.namedArgLoc", match$1[1]);
      var lblLocAttr_1 = {
        TAG: /* PStr */0,
        _0: /* [] */0
      };
      var lblLocAttr = [
        lblLocAttr_0,
        lblLocAttr_1
      ];
      Res_parser.expect(/* TypeExpression */20, /* Colon */24, p);
      var typ = parseTypExpr(undefined, undefined, undefined, p);
      var typ_ptyp_desc = typ.ptyp_desc;
      var typ_ptyp_loc = typ.ptyp_loc;
      var typ_ptyp_attributes = {
        hd: lblLocAttr,
        tl: typ.ptyp_attributes
      };
      var typ$1 = {
        ptyp_desc: typ_ptyp_desc,
        ptyp_loc: typ_ptyp_loc,
        ptyp_attributes: typ_ptyp_attributes
      };
      var match$2 = p.token;
      if (match$2 === 14) {
        Res_parser.next(undefined, p);
        Res_parser.expect(undefined, /* Question */49, p);
        return [
                uncurried,
                attrs,
                {
                  TAG: /* Optional */1,
                  _0: name
                },
                typ$1,
                startPos
              ];
      } else {
        return [
                uncurried,
                attrs,
                {
                  TAG: /* Labelled */0,
                  _0: name
                },
                typ$1,
                startPos
              ];
      }
    }
    
  } else if (match.TAG === /* Lident */4) {
    var match$3 = parseLident(p);
    var loc = match$3[1];
    var name$1 = match$3[0];
    var match$4 = p.token;
    if (match$4 === 24) {
      var error = Res_diagnostics.message(missingTildeLabeledParameter(name$1));
      Res_parser.err(loc.loc_start, loc.loc_end, p, error);
      Res_parser.next(undefined, p);
      var typ$2 = parseTypExpr(undefined, undefined, undefined, p);
      var match$5 = p.token;
      if (match$5 === 14) {
        Res_parser.next(undefined, p);
        Res_parser.expect(undefined, /* Question */49, p);
        return [
                uncurried,
                attrs,
                {
                  TAG: /* Optional */1,
                  _0: name$1
                },
                typ$2,
                startPos
              ];
      } else {
        return [
                uncurried,
                attrs,
                {
                  TAG: /* Labelled */0,
                  _0: name$1
                },
                typ$2,
                startPos
              ];
      }
    }
    var constr = $$Location.mkloc({
          TAG: /* Lident */0,
          _0: name$1
        }, loc);
    var args = parseTypeConstructorArgs(constr, p);
    var typ$3 = Ast_helper.Typ.constr({
          loc_start: startPos,
          loc_end: p.prevEndPos,
          loc_ghost: false
        }, attrs, constr, args);
    var typ$4 = parseArrowTypeRest(true, startPos, typ$3, p);
    var typ$5 = parseTypeAlias(p, typ$4);
    return [
            uncurried,
            /* [] */0,
            /* Nolabel */0,
            typ$5,
            startPos
          ];
  }
  var typ$6 = parseTypExpr(undefined, undefined, undefined, p);
  var typWithAttributes_ptyp_desc = typ$6.ptyp_desc;
  var typWithAttributes_ptyp_loc = typ$6.ptyp_loc;
  var typWithAttributes_ptyp_attributes = List.concat({
        hd: attrs,
        tl: {
          hd: typ$6.ptyp_attributes,
          tl: /* [] */0
        }
      });
  var typWithAttributes = {
    ptyp_desc: typWithAttributes_ptyp_desc,
    ptyp_loc: typWithAttributes_ptyp_loc,
    ptyp_attributes: typWithAttributes_ptyp_attributes
  };
  return [
          uncurried,
          /* [] */0,
          /* Nolabel */0,
          typWithAttributes,
          startPos
        ];
}

function parseRecordDeclaration(p) {
  Res_parser.leaveBreadcrumb(p, /* RecordDecl */34);
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var rows = parseCommaDelimitedRegion(p, /* RecordDecl */34, /* Rbrace */23, parseFieldDeclarationRegion);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  Res_parser.eatBreadcrumb(p);
  return rows;
}

function parseStructureItemRegion(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var token = p.token;
  if (typeof token === "number") {
    if (token >= 10) {
      if (token !== 27) {
        if (token >= 59) {
          switch (token) {
            case /* External */59 :
                var externalDef = parseExternalDef(attrs, startPos, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end = p.prevEndPos;
                var loc = {
                  loc_start: startPos,
                  loc_end: loc_loc_end,
                  loc_ghost: false
                };
                return Ast_helper.Str.primitive(loc, externalDef);
            case /* Typ */60 :
                Res_parser.beginRegion(p);
                var ext = parseTypeDefinitionOrExtension(attrs, p);
                if (ext.TAG === /* TypeDef */0) {
                  parseNewlineOrSemicolonStructure(p);
                  var loc_loc_end$1 = p.prevEndPos;
                  var loc$1 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$1,
                    loc_ghost: false
                  };
                  Res_parser.endRegion(p);
                  return Ast_helper.Str.type_(loc$1, ext.recFlag, ext.types);
                }
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$2 = p.prevEndPos;
                var loc$2 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$2,
                  loc_ghost: false
                };
                Res_parser.endRegion(p);
                return Ast_helper.Str.type_extension(loc$2, ext._0);
            case /* Include */64 :
                var includeStatement = parseIncludeStatement(attrs, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$3 = p.prevEndPos;
                var loc$3 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$3,
                  loc_ghost: false
                };
                return Ast_helper.Str.include_(loc$3, includeStatement);
            case /* Module */65 :
                Res_parser.beginRegion(p);
                var structureItem = parseModuleOrModuleTypeImplOrPackExpr(attrs, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$4 = p.prevEndPos;
                var loc$4 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$4,
                  loc_ghost: false
                };
                Res_parser.endRegion(p);
                return {
                        pstr_desc: structureItem.pstr_desc,
                        pstr_loc: loc$4
                      };
            case /* AtAt */76 :
                var attr = parseStandaloneAttribute(p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$5 = p.prevEndPos;
                var loc$5 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$5,
                  loc_ghost: false
                };
                return Ast_helper.Str.attribute(loc$5, attr);
            case /* PercentPercent */78 :
                var extension = parseExtension(true, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$6 = p.prevEndPos;
                var loc$6 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$6,
                  loc_ghost: false
                };
                return Ast_helper.Str.extension(loc$6, attrs, extension);
            case /* Private */61 :
            case /* Mutable */62 :
            case /* Constraint */63 :
            case /* Of */66 :
            case /* Land */67 :
            case /* Lor */68 :
            case /* Band */69 :
            case /* BangEqual */70 :
            case /* BangEqualEqual */71 :
            case /* LessEqual */72 :
            case /* GreaterEqual */73 :
            case /* ColonEqual */74 :
            case /* At */75 :
            case /* Percent */77 :
            case /* List */79 :
            case /* Backtick */80 :
            case /* BarGreater */81 :
            case /* Try */82 :
                break;
            case /* Import */83 :
                var importDescr = parseJsImport(startPos, attrs, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$7 = p.prevEndPos;
                var loc$7 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$7,
                  loc_ghost: false
                };
                var structureItem$1 = Res_js_ffi.toParsetree(importDescr);
                return {
                        pstr_desc: structureItem$1.pstr_desc,
                        pstr_loc: loc$7
                      };
            case /* Export */84 :
                var structureItem$2 = parseJsExport(attrs, p);
                parseNewlineOrSemicolonStructure(p);
                var loc_loc_end$8 = p.prevEndPos;
                var loc$8 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$8,
                  loc_ghost: false
                };
                return {
                        pstr_desc: structureItem$2.pstr_desc,
                        pstr_loc: loc$8
                      };
            
          }
        }
        
      } else {
        var exceptionDef = parseExceptionDef(attrs, p);
        parseNewlineOrSemicolonStructure(p);
        var loc_loc_end$9 = p.prevEndPos;
        var loc$9 = {
          loc_start: startPos,
          loc_end: loc_loc_end$9,
          loc_ghost: false
        };
        return Ast_helper.Str.exception_(loc$9, exceptionDef);
      }
    } else if (token !== 0) {
      if (token >= 9) {
        var match = parseLetBindings(attrs, p);
        parseNewlineOrSemicolonStructure(p);
        var loc_loc_end$10 = p.prevEndPos;
        var loc$10 = {
          loc_start: startPos,
          loc_end: loc_loc_end$10,
          loc_ghost: false
        };
        return Ast_helper.Str.value(loc$10, match[0], match[1]);
      }
      
    } else {
      var openDescription = parseOpenDescription(attrs, p);
      parseNewlineOrSemicolonStructure(p);
      var loc_loc_end$11 = p.prevEndPos;
      var loc$11 = {
        loc_start: startPos,
        loc_end: loc_loc_end$11,
        loc_ghost: false
      };
      return Ast_helper.Str.open_(loc$11, openDescription);
    }
  }
  if (Res_grammar.isExprStart(token)) {
    var prevEndPos = p.endPos;
    var exp = parseExpr(undefined, p);
    parseNewlineOrSemicolonStructure(p);
    var loc_loc_end$12 = p.prevEndPos;
    var loc$12 = {
      loc_start: startPos,
      loc_end: loc_loc_end$12,
      loc_ghost: false
    };
    return Res_parser.checkProgress(prevEndPos, Ast_helper.Str.$$eval(loc$12, attrs, exp), p);
  }
  if (!attrs) {
    return ;
  }
  var attr$1 = attrs.hd;
  var attrLoc = attr$1[0].loc;
  Res_parser.err(attrLoc.loc_start, attrLoc.loc_end, p, Res_diagnostics.message(attributeWithoutNode(attr$1)));
  var expr = parseExpr(undefined, p);
  return Ast_helper.Str.$$eval({
              loc_start: p.startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, attrs, expr);
}

function parseSignatureItemRegion(p) {
  while(true) {
    var startPos = p.startPos;
    var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
    var match = p.token;
    if (typeof match === "number") {
      if (match >= 10) {
        if (match !== 27) {
          if (match >= 59) {
            switch (match) {
              case /* External */59 :
                  var externalDef = parseExternalDef(attrs, startPos, p);
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end = p.prevEndPos;
                  var loc = {
                    loc_start: startPos,
                    loc_end: loc_loc_end,
                    loc_ghost: false
                  };
                  return Ast_helper.Sig.value(loc, externalDef);
              case /* Typ */60 :
                  Res_parser.beginRegion(p);
                  var ext = parseTypeDefinitionOrExtension(attrs, p);
                  if (ext.TAG === /* TypeDef */0) {
                    parseNewlineOrSemicolonSignature(p);
                    var loc_loc_end$1 = p.prevEndPos;
                    var loc$1 = {
                      loc_start: startPos,
                      loc_end: loc_loc_end$1,
                      loc_ghost: false
                    };
                    Res_parser.endRegion(p);
                    return Ast_helper.Sig.type_(loc$1, ext.recFlag, ext.types);
                  }
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end$2 = p.prevEndPos;
                  var loc$2 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$2,
                    loc_ghost: false
                  };
                  Res_parser.endRegion(p);
                  return Ast_helper.Sig.type_extension(loc$2, ext._0);
              case /* Include */64 :
                  Res_parser.next(undefined, p);
                  var moduleType = parseModuleType(undefined, undefined, p);
                  var includeDescription = Ast_helper.Incl.mk({
                        loc_start: startPos,
                        loc_end: p.prevEndPos,
                        loc_ghost: false
                      }, attrs, undefined, moduleType);
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end$3 = p.prevEndPos;
                  var loc$3 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$3,
                    loc_ghost: false
                  };
                  return Ast_helper.Sig.include_(loc$3, includeDescription);
              case /* Module */65 :
                  Res_parser.beginRegion(p);
                  Res_parser.next(undefined, p);
                  var _t = p.token;
                  var exit = 0;
                  if (typeof _t === "number") {
                    switch (_t) {
                      case /* Rec */11 :
                          var recModule = parseRecModuleSpec(attrs, startPos, p);
                          parseNewlineOrSemicolonSignature(p);
                          var loc_loc_end$4 = p.prevEndPos;
                          var loc$4 = {
                            loc_start: startPos,
                            loc_end: loc_loc_end$4,
                            loc_ghost: false
                          };
                          Res_parser.endRegion(p);
                          return Ast_helper.Sig.rec_module(loc$4, recModule);
                      case /* Typ */60 :
                          var modTypeDecl = parseModuleTypeDeclaration(attrs, startPos, p);
                          Res_parser.endRegion(p);
                          return modTypeDecl;
                      default:
                        exit = 2;
                    }
                  } else {
                    if (_t.TAG === /* Uident */5) {
                      var modDecl = parseModuleDeclarationOrAlias(attrs, p);
                      parseNewlineOrSemicolonSignature(p);
                      var loc_loc_end$5 = p.prevEndPos;
                      var loc$5 = {
                        loc_start: startPos,
                        loc_end: loc_loc_end$5,
                        loc_ghost: false
                      };
                      Res_parser.endRegion(p);
                      return Ast_helper.Sig.module_(loc$5, modDecl);
                    }
                    exit = 2;
                  }
                  if (exit === 2) {
                    var modDecl$1 = parseModuleDeclarationOrAlias(attrs, p);
                    parseNewlineOrSemicolonSignature(p);
                    var loc_loc_end$6 = p.prevEndPos;
                    var loc$6 = {
                      loc_start: startPos,
                      loc_end: loc_loc_end$6,
                      loc_ghost: false
                    };
                    Res_parser.endRegion(p);
                    return Ast_helper.Sig.module_(loc$6, modDecl$1);
                  }
                  break;
              case /* AtAt */76 :
                  var attr = parseStandaloneAttribute(p);
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end$7 = p.prevEndPos;
                  var loc$7 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$7,
                    loc_ghost: false
                  };
                  return Ast_helper.Sig.attribute(loc$7, attr);
              case /* PercentPercent */78 :
                  var extension = parseExtension(true, p);
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end$8 = p.prevEndPos;
                  var loc$8 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$8,
                    loc_ghost: false
                  };
                  return Ast_helper.Sig.extension(loc$8, attrs, extension);
              case /* Private */61 :
              case /* Mutable */62 :
              case /* Constraint */63 :
              case /* Of */66 :
              case /* Land */67 :
              case /* Lor */68 :
              case /* Band */69 :
              case /* BangEqual */70 :
              case /* BangEqualEqual */71 :
              case /* LessEqual */72 :
              case /* GreaterEqual */73 :
              case /* ColonEqual */74 :
              case /* At */75 :
              case /* Percent */77 :
              case /* List */79 :
              case /* Backtick */80 :
              case /* BarGreater */81 :
              case /* Try */82 :
                  break;
              case /* Import */83 :
                  Res_parser.next(undefined, p);
                  continue ;
              case /* Export */84 :
                  var signatureItem = parseSignJsExport(attrs, p);
                  parseNewlineOrSemicolonSignature(p);
                  var loc_loc_end$9 = p.prevEndPos;
                  var loc$9 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$9,
                    loc_ghost: false
                  };
                  return {
                          psig_desc: signatureItem.psig_desc,
                          psig_loc: loc$9
                        };
              
            }
          }
          
        } else {
          var exceptionDef = parseExceptionDef(attrs, p);
          parseNewlineOrSemicolonSignature(p);
          var loc_loc_end$10 = p.prevEndPos;
          var loc$10 = {
            loc_start: startPos,
            loc_end: loc_loc_end$10,
            loc_ghost: false
          };
          return Ast_helper.Sig.exception_(loc$10, exceptionDef);
        }
      } else if (match !== 0) {
        if (match >= 9) {
          Res_parser.beginRegion(p);
          var valueDesc = parseSignLetDesc(attrs, p);
          parseNewlineOrSemicolonSignature(p);
          var loc_loc_end$11 = p.prevEndPos;
          var loc$11 = {
            loc_start: startPos,
            loc_end: loc_loc_end$11,
            loc_ghost: false
          };
          Res_parser.endRegion(p);
          return Ast_helper.Sig.value(loc$11, valueDesc);
        }
        
      } else {
        var openDescription = parseOpenDescription(attrs, p);
        parseNewlineOrSemicolonSignature(p);
        var loc_loc_end$12 = p.prevEndPos;
        var loc$12 = {
          loc_start: startPos,
          loc_end: loc_loc_end$12,
          loc_ghost: false
        };
        return Ast_helper.Sig.open_(loc$12, openDescription);
      }
    }
    if (!attrs) {
      return ;
    }
    var attr$1 = attrs.hd;
    var attrLoc = attr$1[0].loc;
    Res_parser.err(attrLoc.loc_start, attrLoc.loc_end, p, Res_diagnostics.message(attributeWithoutNode(attr$1)));
    return defaultSignatureItem;
  };
}

function parseNonSpreadExp(msg, p) {
  var match = p.token;
  if (match === 6) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message(msg));
    Res_parser.next(undefined, p);
  }
  var token = p.token;
  if (!Res_grammar.isExprStart(token)) {
    return ;
  }
  var expr = parseExpr(undefined, p);
  var match$1 = p.token;
  if (match$1 !== 24) {
    return expr;
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = expr.pexp_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.constraint_(loc, undefined, expr, typ);
}

function parseTypeParameters(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var match = p.token;
  if (match === 19) {
    Res_parser.next(undefined, p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    var unitConstr = $$Location.mkloc({
          TAG: /* Lident */0,
          _0: "unit"
        }, loc);
    var typ = Ast_helper.Typ.constr(undefined, undefined, unitConstr, /* [] */0);
    return {
            hd: [
              false,
              /* [] */0,
              /* Nolabel */0,
              typ,
              startPos
            ],
            tl: /* [] */0
          };
  }
  var params = parseCommaDelimitedRegion(p, /* TypeParameters */42, /* Rparen */19, parseTypeParameter);
  Res_parser.expect(undefined, /* Rparen */19, p);
  return params;
}

function parsePatternGuard(p) {
  var match = p.token;
  if (typeof match !== "number") {
    return ;
  }
  if (match !== 50 && match !== 56) {
    return ;
  }
  Res_parser.next(undefined, p);
  return parseExpr(/* WhenExpr */2, p);
}

function parseRecModuleDeclaration(attrs, startPos, p) {
  var modName = p.token;
  var name;
  var exit = 0;
  if (typeof modName === "number" || modName.TAG !== /* Uident */5) {
    exit = 1;
  } else {
    var loc_loc_start = p.startPos;
    var loc_loc_end = p.endPos;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    name = $$Location.mkloc(modName._0, loc);
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(modName));
    name = $$Location.mknoloc("_");
  }
  Res_parser.expect(undefined, /* Colon */24, p);
  var modType = parseModuleType(undefined, undefined, p);
  return Ast_helper.Md.mk({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, attrs, undefined, undefined, name, modType);
}

function parseEs6ArrowExpression(context, parameters, p) {
  var startPos = p.startPos;
  Res_parser.leaveBreadcrumb(p, /* Es6ArrowExpr */3);
  var parameters$1 = parameters !== undefined ? parameters : parseParameters(p);
  var match = p.token;
  var returnType = match === 24 ? (Res_parser.next(undefined, p), parseTypExpr(undefined, false, undefined, p)) : undefined;
  Res_parser.expect(undefined, /* EqualGreater */57, p);
  var expr = parseExpr(context, p);
  var body = returnType !== undefined ? Ast_helper.Exp.constraint_({
          loc_start: expr.pexp_loc.loc_start,
          loc_end: returnType.ptyp_loc.loc_end,
          loc_ghost: false
        }, undefined, expr, returnType) : expr;
  Res_parser.eatBreadcrumb(p);
  var endPos = p.prevEndPos;
  var arrowExpr = List.fold_right((function (parameter, expr) {
          if (parameter.TAG === /* TermParameter */0) {
            var attrs = parameter.attrs;
            var attrs$1 = parameter.uncurried ? ({
                  hd: uncurryAttr,
                  tl: attrs
                }) : attrs;
            return Ast_helper.Exp.fun_({
                        loc_start: parameter.pos,
                        loc_end: endPos,
                        loc_ghost: false
                      }, attrs$1, parameter.label, parameter.expr, parameter.pat, expr);
          }
          var attrs$2 = parameter.attrs;
          var attrs$3 = parameter.uncurried ? ({
                hd: uncurryAttr,
                tl: attrs$2
              }) : attrs$2;
          return makeNewtypes(attrs$3, {
                      loc_start: parameter.pos,
                      loc_end: endPos,
                      loc_ghost: false
                    }, parameter.locs, expr);
        }), parameters$1, body);
  var init = arrowExpr.pexp_loc;
  return {
          pexp_desc: arrowExpr.pexp_desc,
          pexp_loc: {
            loc_start: startPos,
            loc_end: init.loc_end,
            loc_ghost: init.loc_ghost
          },
          pexp_attributes: arrowExpr.pexp_attributes
        };
}

function parseRecordExprWithStringKeys(startPos, firstRow, p) {
  var rows_1 = parseCommaDelimitedRegion(p, /* RecordRowsStringKey */44, /* Rbrace */23, parseRecordRowWithStringKey);
  var rows = {
    hd: firstRow,
    tl: rows_1
  };
  var loc_loc_end = p.endPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var recordStrExpr = Ast_helper.Str.$$eval(loc, undefined, Ast_helper.Exp.record(loc, undefined, rows, undefined));
  return Ast_helper.Exp.extension(loc, undefined, [
              $$Location.mkloc("obj", loc),
              {
                TAG: /* PStr */0,
                _0: {
                  hd: recordStrExpr,
                  tl: /* [] */0
                }
              }
            ]);
}

function parseRecordExpr(startPos, spreadOpt, rows, p) {
  var spread = spreadOpt !== undefined ? Caml_option.valFromOption(spreadOpt) : undefined;
  var exprs = parseCommaDelimitedRegion(p, /* RecordRows */43, /* Rbrace */23, parseRecordRow);
  var rows$1 = List.concat({
        hd: rows,
        tl: {
          hd: exprs,
          tl: /* [] */0
        }
      });
  if (rows$1) {
    
  } else {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message("Record spread needs at least one field that's updated"));
  }
  var loc_loc_end = p.endPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.record(loc, undefined, rows$1, spread);
}

function parseValueOrConstructor(p) {
  var startPos = p.startPos;
  var _acc = /* [] */0;
  while(true) {
    var acc = _acc;
    var ident = p.token;
    if (typeof ident !== "number") {
      switch (ident.TAG | 0) {
        case /* Lident */4 :
            Res_parser.next(undefined, p);
            var loc_loc_end = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var lident = buildLongident({
                  hd: ident._0,
                  tl: acc
                });
            return Ast_helper.Exp.ident(loc, undefined, $$Location.mkloc(lident, loc));
        case /* Uident */5 :
            var ident$1 = ident._0;
            var endPosLident = p.endPos;
            Res_parser.next(undefined, p);
            var match = p.token;
            var exit = 0;
            if (typeof match === "number") {
              if (match !== 4) {
                if (match !== 18) {
                  exit = 2;
                } else {
                  if (p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
                    var lparen = p.startPos;
                    var args = parseConstructorArgs(p);
                    var rparen = p.prevEndPos;
                    var lident$1 = buildLongident({
                          hd: ident$1,
                          tl: acc
                        });
                    var tail;
                    var exit$1 = 0;
                    if (args) {
                      var arg = args.hd;
                      var tmp = arg.pexp_desc;
                      if (typeof tmp === "number") {
                        if (args.tl) {
                          exit$1 = 3;
                        } else {
                          tail = arg;
                        }
                      } else if (tmp.TAG === /* Pexp_tuple */8) {
                        if (args.tl) {
                          exit$1 = 3;
                        } else {
                          var loc$1 = {
                            loc_start: lparen,
                            loc_end: rparen,
                            loc_ghost: false
                          };
                          tail = p.mode === /* ParseForTypeChecker */0 ? arg : Ast_helper.Exp.tuple(loc$1, undefined, args);
                        }
                      } else if (args.tl) {
                        exit$1 = 3;
                      } else {
                        tail = arg;
                      }
                    } else {
                      tail = undefined;
                    }
                    if (exit$1 === 3) {
                      var loc$2 = {
                        loc_start: lparen,
                        loc_end: rparen,
                        loc_ghost: false
                      };
                      tail = Ast_helper.Exp.tuple(loc$2, undefined, args);
                    }
                    var loc_loc_end$1 = p.prevEndPos;
                    var loc$3 = {
                      loc_start: startPos,
                      loc_end: loc_loc_end$1,
                      loc_ghost: false
                    };
                    var identLoc = {
                      loc_start: startPos,
                      loc_end: endPosLident,
                      loc_ghost: false
                    };
                    return Ast_helper.Exp.construct(loc$3, undefined, $$Location.mkloc(lident$1, identLoc), tail);
                  }
                  exit = 2;
                }
              } else {
                Res_parser.next(undefined, p);
                _acc = {
                  hd: ident$1,
                  tl: acc
                };
                continue ;
              }
            } else {
              exit = 2;
            }
            if (exit === 2) {
              var loc_loc_end$2 = p.prevEndPos;
              var loc$4 = {
                loc_start: startPos,
                loc_end: loc_loc_end$2,
                loc_ghost: false
              };
              var lident$2 = buildLongident({
                    hd: ident$1,
                    tl: acc
                  });
              return Ast_helper.Exp.construct(loc$4, undefined, $$Location.mkloc(lident$2, loc$4), undefined);
            }
            break;
        default:
          
      }
    }
    if (acc === /* [] */0) {
      Res_parser.next(undefined, p);
      Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident, p.breadcrumbs));
      return defaultExpr(undefined);
    }
    var loc_loc_end$3 = p.prevEndPos;
    var loc$5 = {
      loc_start: startPos,
      loc_end: loc_loc_end$3,
      loc_ghost: false
    };
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident, p.breadcrumbs));
    var lident$3 = buildLongident({
          hd: "_",
          tl: acc
        });
    return Ast_helper.Exp.ident(loc$5, undefined, $$Location.mkloc(lident$3, loc$5));
  };
}

function parseAtomicExpr(p) {
  Res_parser.leaveBreadcrumb(p, /* ExprOperand */7);
  var startPos = p.startPos;
  var token = p.token;
  var expr;
  var exit = 0;
  if (typeof token === "number") {
    switch (token) {
      case /* True */1 :
      case /* False */2 :
          exit = 2;
          break;
      case /* Underscore */12 :
          Res_parser.err(undefined, undefined, p, Res_diagnostics.lident(token));
          Res_parser.next(undefined, p);
          expr = defaultExpr(undefined);
          break;
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var _t = p.token;
          if (_t === 19) {
            Res_parser.next(undefined, p);
            var loc_loc_end = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            expr = Ast_helper.Exp.construct(loc, undefined, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: "()"
                    }, loc), undefined);
          } else {
            var expr$1 = parseConstrainedOrCoercedExpr(p);
            var match = p.token;
            if (match === 25) {
              Res_parser.next(undefined, p);
              expr = parseTupleExpr(expr$1, startPos, p);
            } else {
              Res_parser.expect(undefined, /* Rparen */19, p);
              expr = expr$1;
            }
          }
          break;
      case /* Lbracket */20 :
          expr = parseArrayExp(p);
          break;
      case /* Lbrace */22 :
          expr = parseBracedOrRecordExpr(p);
          break;
      case /* LessThan */42 :
          expr = parseJsx(p);
          break;
      case /* Hash */44 :
          expr = parsePolyVariantExpr(p);
          break;
      case /* Module */65 :
          Res_parser.next(undefined, p);
          expr = parseFirstClassModuleExpr(startPos, p);
          break;
      case /* Percent */77 :
          var extension = parseExtension(undefined, p);
          var loc_loc_end$1 = p.prevEndPos;
          var loc$1 = {
            loc_start: startPos,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          expr = Ast_helper.Exp.extension(loc$1, undefined, extension);
          break;
      case /* List */79 :
          Res_parser.next(undefined, p);
          expr = parseListExpr(startPos, p);
          break;
      case /* Backtick */80 :
          var expr$2 = parseTemplateExpr(undefined, p);
          expr = {
            pexp_desc: expr$2.pexp_desc,
            pexp_loc: {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            },
            pexp_attributes: expr$2.pexp_attributes
          };
          break;
      default:
        exit = 1;
    }
  } else {
    switch (token.TAG | 0) {
      case /* Codepoint */0 :
      case /* Int */1 :
      case /* Float */2 :
      case /* String */3 :
          exit = 3;
          break;
      case /* Lident */4 :
      case /* Uident */5 :
          expr = parseValueOrConstructor(p);
          break;
      default:
        exit = 1;
    }
  }
  switch (exit) {
    case 1 :
        var errPos = p.prevEndPos;
        Res_parser.err(errPos, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
        var match$1 = skipTokensAndMaybeRetry(p, Res_grammar.isAtomicExprStart);
        expr = match$1 !== undefined ? parseAtomicExpr(p) : defaultExpr(undefined);
        break;
    case 2 :
        Res_parser.next(undefined, p);
        var loc_loc_end$2 = p.prevEndPos;
        var loc$2 = {
          loc_start: startPos,
          loc_end: loc_loc_end$2,
          loc_ghost: false
        };
        expr = Ast_helper.Exp.construct(loc$2, undefined, $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: Res_token.toString(token)
                }, loc$2), undefined);
        break;
    case 3 :
        var c = parseConstant(p);
        var loc_loc_end$3 = p.prevEndPos;
        var loc$3 = {
          loc_start: startPos,
          loc_end: loc_loc_end$3,
          loc_ghost: false
        };
        expr = Ast_helper.Exp.constant(loc$3, undefined, c);
        break;
    
  }
  Res_parser.eatBreadcrumb(p);
  return expr;
}

function parseRecordPatternItem(p) {
  var match = p.token;
  if (typeof match === "number") {
    switch (match) {
      case /* DotDotDot */6 :
          Res_parser.next(undefined, p);
          return [
                  true,
                  /* PatField */{
                    _0: parseRecordPatternField(p)
                  }
                ];
      case /* Underscore */12 :
          Res_parser.next(undefined, p);
          return [
                  false,
                  /* PatUnderscore */0
                ];
      default:
        return ;
    }
  } else {
    switch (match.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          return [
                  false,
                  /* PatField */{
                    _0: parseRecordPatternField(p)
                  }
                ];
      default:
        return ;
    }
  }
}

function parsePackageConstraints(p) {
  Res_parser.expect(undefined, /* Typ */60, p);
  var typeConstr = parseValuePath(p);
  Res_parser.expect(undefined, /* Equal */14, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var first = [
    typeConstr,
    typ
  ];
  var rest = parseRegion(p, /* PackageConstraint */32, parsePackageConstraint);
  return {
          hd: first,
          tl: rest
        };
}

function parseConstrainedExprRegion(p) {
  var token = p.token;
  if (!Res_grammar.isExprStart(token)) {
    return ;
  }
  var expr = parseExpr(undefined, p);
  var match = p.token;
  if (match !== 24) {
    return expr;
  }
  Res_parser.next(undefined, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = expr.pexp_loc.loc_start;
  var loc_loc_end = typ.ptyp_loc.loc_end;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.constraint_(loc, undefined, expr, typ);
}

function parseTagName(p) {
  var match = p.token;
  if (match !== 44) {
    return ;
  }
  var match$1 = parseHashIdent(p.startPos, p);
  return match$1[0];
}

function parseFunctorModuleType(p) {
  var startPos = p.startPos;
  var args = parseFunctorArgs(p);
  Res_parser.expect(undefined, /* EqualGreater */57, p);
  var rhs = parseModuleType(undefined, undefined, p);
  var endPos = p.prevEndPos;
  var modType = List.fold_right((function (param, acc) {
          return Ast_helper.Mty.functor_({
                      loc_start: param[3],
                      loc_end: endPos,
                      loc_ghost: false
                    }, param[0], param[1], param[2], acc);
        }), args, rhs);
  return {
          pmty_desc: modType.pmty_desc,
          pmty_loc: {
            loc_start: startPos,
            loc_end: endPos,
            loc_ghost: false
          },
          pmty_attributes: modType.pmty_attributes
        };
}

function parseWithConstraints(moduleType, p) {
  var match = p.token;
  if (typeof match === "number") {
    return moduleType;
  }
  if (match.TAG !== /* Lident */4) {
    return moduleType;
  }
  if (match._0 !== "with") {
    return moduleType;
  }
  Res_parser.next(undefined, p);
  var first = parseWithConstraint(p);
  var loop = function (p, _acc) {
    while(true) {
      var acc = _acc;
      var match = p.token;
      if (match !== 10) {
        return List.rev(acc);
      }
      Res_parser.next(undefined, p);
      _acc = {
        hd: parseWithConstraint(p),
        tl: acc
      };
      continue ;
    };
  };
  var constraints = loop(p, {
        hd: first,
        tl: /* [] */0
      });
  var loc_loc_start = moduleType.pmty_loc.loc_start;
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Mty.with_(loc, undefined, moduleType, constraints);
}

function parseAtomicModuleType(p) {
  var startPos = p.startPos;
  var token = p.token;
  var moduleType;
  var exit = 0;
  if (typeof token === "number") {
    switch (token) {
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var mty = parseModuleType(undefined, undefined, p);
          Res_parser.expect(undefined, /* Rparen */19, p);
          moduleType = {
            pmty_desc: mty.pmty_desc,
            pmty_loc: {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            },
            pmty_attributes: mty.pmty_attributes
          };
          break;
      case /* Lbrace */22 :
          Res_parser.next(undefined, p);
          var spec = parseDelimitedRegion(p, /* Signature */46, /* Rbrace */23, parseSignatureItemRegion);
          Res_parser.expect(undefined, /* Rbrace */23, p);
          var loc_loc_end = p.prevEndPos;
          var loc = {
            loc_start: startPos,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          moduleType = Ast_helper.Mty.signature(loc, undefined, spec);
          break;
      case /* Module */65 :
          moduleType = parseModuleTypeOf(p);
          break;
      case /* Percent */77 :
          var extension = parseExtension(undefined, p);
          var loc_loc_end$1 = p.prevEndPos;
          var loc$1 = {
            loc_start: startPos,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          moduleType = Ast_helper.Mty.extension(loc$1, undefined, extension);
          break;
      default:
        exit = 1;
    }
  } else {
    switch (token.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 2;
          break;
      default:
        exit = 1;
    }
  }
  switch (exit) {
    case 1 :
        Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
        moduleType = defaultModuleType(undefined);
        break;
    case 2 :
        var moduleLongIdent = parseModuleLongIdent(true, p);
        moduleType = Ast_helper.Mty.ident(moduleLongIdent.loc, undefined, moduleLongIdent);
        break;
    
  }
  var moduleTypeLoc_loc_end = p.prevEndPos;
  var moduleTypeLoc = {
    loc_start: startPos,
    loc_end: moduleTypeLoc_loc_end,
    loc_ghost: false
  };
  return {
          pmty_desc: moduleType.pmty_desc,
          pmty_loc: moduleTypeLoc,
          pmty_attributes: moduleType.pmty_attributes
        };
}

function parseFunctorArgs(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var args = parseCommaDelimitedRegion(p, /* FunctorArgs */40, /* Rparen */19, parseFunctorArg);
  Res_parser.expect(undefined, /* Rparen */19, p);
  if (args) {
    return args;
  } else {
    return {
            hd: [
              /* [] */0,
              $$Location.mkloc("*", {
                    loc_start: startPos,
                    loc_end: p.prevEndPos,
                    loc_ghost: false
                  }),
              undefined,
              startPos
            ],
            tl: /* [] */0
          };
  }
}

function parseFunctorArg(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var ident = p.token;
  if (typeof ident === "number") {
    switch (ident) {
      case /* Underscore */12 :
          Res_parser.next(undefined, p);
          var argName = $$Location.mkloc("_", {
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              });
          Res_parser.expect(undefined, /* Colon */24, p);
          var moduleType = parseModuleType(undefined, undefined, p);
          return [
                  attrs,
                  argName,
                  moduleType,
                  startPos
                ];
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          Res_parser.expect(undefined, /* Rparen */19, p);
          var argName$1 = $$Location.mkloc("*", {
                loc_start: startPos,
                loc_end: p.prevEndPos,
                loc_ghost: false
              });
          return [
                  attrs,
                  argName$1,
                  undefined,
                  startPos
                ];
      default:
        return ;
    }
  } else {
    if (ident.TAG !== /* Uident */5) {
      return ;
    }
    var ident$1 = ident._0;
    Res_parser.next(undefined, p);
    var uidentEndPos = p.prevEndPos;
    var match = p.token;
    if (typeof match === "number") {
      if (match !== 4) {
        if (match === 24) {
          Res_parser.next(undefined, p);
          var moduleType$1 = parseModuleType(undefined, undefined, p);
          var loc = {
            loc_start: startPos,
            loc_end: uidentEndPos,
            loc_ghost: false
          };
          var argName$2 = $$Location.mkloc(ident$1, loc);
          return [
                  attrs,
                  argName$2,
                  moduleType$1,
                  startPos
                ];
        }
        
      } else {
        Res_parser.next(undefined, p);
        var moduleLongIdent = parseModuleLongIdentTail(false, p, startPos, {
              TAG: /* Lident */0,
              _0: ident$1
            });
        var moduleType$2 = Ast_helper.Mty.ident(moduleLongIdent.loc, undefined, moduleLongIdent);
        var argName$3 = $$Location.mknoloc("_");
        return [
                attrs,
                argName$3,
                moduleType$2,
                startPos
              ];
      }
    }
    var loc$1 = {
      loc_start: startPos,
      loc_end: uidentEndPos,
      loc_ghost: false
    };
    var modIdent = $$Location.mkloc({
          TAG: /* Lident */0,
          _0: ident$1
        }, loc$1);
    var moduleType$3 = Ast_helper.Mty.ident(loc$1, undefined, modIdent);
    var argName$4 = $$Location.mknoloc("_");
    return [
            attrs,
            argName$4,
            moduleType$3,
            startPos
          ];
  }
}

function parsePrivateEqOrRepr(p) {
  Res_parser.expect(undefined, /* Private */61, p);
  var t = p.token;
  var exit = 0;
  if (typeof t === "number") {
    switch (t) {
      case /* DotDot */5 :
      case /* Bar */17 :
          exit = 2;
          break;
      case /* Lbrace */22 :
          var match = parseRecordOrObjectDecl(p);
          return [
                  match[0],
                  /* Private */0,
                  match[2]
                ];
      default:
        exit = 1;
    }
  } else {
    if (t.TAG === /* Uident */5) {
      var match$1 = parseTypeEquationOrConstrDecl(p);
      return [
              match$1[0],
              /* Private */0,
              match$1[2]
            ];
    }
    exit = 1;
  }
  switch (exit) {
    case 1 :
        if (Res_grammar.isTypExprStart(t)) {
          return [
                  parseTypExpr(undefined, undefined, undefined, p),
                  /* Private */0,
                  /* Ptype_abstract */0
                ];
        }
        var match$2 = parseTypeRepresentation(p);
        return [
                undefined,
                /* Private */0,
                match$2[1]
              ];
    case 2 :
        var match$3 = parseTypeRepresentation(p);
        return [
                undefined,
                /* Private */0,
                match$3[1]
              ];
    
  }
}

function parseAtomicModuleExpr(p) {
  var startPos = p.startPos;
  var _ident = p.token;
  if (typeof _ident === "number") {
    switch (_ident) {
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var match = p.token;
          var modExpr = match === 19 ? Ast_helper.Mod.structure({
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                }, undefined, /* [] */0) : parseConstrainedModExpr(p);
          Res_parser.expect(undefined, /* Rparen */19, p);
          return modExpr;
      case /* Lbrace */22 :
          Res_parser.next(undefined, p);
          var structure = Ast_helper.Mod.structure(undefined, undefined, parseDelimitedRegion(p, /* Structure */48, /* Rbrace */23, parseStructureItemRegion));
          Res_parser.expect(undefined, /* Rbrace */23, p);
          var endPos = p.prevEndPos;
          return {
                  pmod_desc: structure.pmod_desc,
                  pmod_loc: {
                    loc_start: startPos,
                    loc_end: endPos,
                    loc_ghost: false
                  },
                  pmod_attributes: structure.pmod_attributes
                };
      case /* Percent */77 :
          var extension = parseExtension(undefined, p);
          var loc_loc_end = p.prevEndPos;
          var loc = {
            loc_start: startPos,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          return Ast_helper.Mod.extension(loc, undefined, extension);
      default:
        
    }
  } else {
    switch (_ident.TAG | 0) {
      case /* Lident */4 :
          if (_ident._0 === "unpack") {
            Res_parser.next(undefined, p);
            Res_parser.expect(undefined, /* Lparen */18, p);
            var expr = parseExpr(undefined, p);
            var match$1 = p.token;
            if (match$1 === 24) {
              var colonStart = p.startPos;
              Res_parser.next(undefined, p);
              var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
              var packageType = parsePackageType(colonStart, attrs, p);
              Res_parser.expect(undefined, /* Rparen */19, p);
              var loc_loc_end$1 = p.prevEndPos;
              var loc$1 = {
                loc_start: startPos,
                loc_end: loc_loc_end$1,
                loc_ghost: false
              };
              var constraintExpr = Ast_helper.Exp.constraint_(loc$1, undefined, expr, packageType);
              return Ast_helper.Mod.unpack(loc$1, undefined, constraintExpr);
            }
            Res_parser.expect(undefined, /* Rparen */19, p);
            var loc_loc_end$2 = p.prevEndPos;
            var loc$2 = {
              loc_start: startPos,
              loc_end: loc_loc_end$2,
              loc_ghost: false
            };
            return Ast_helper.Mod.unpack(loc$2, undefined, expr);
          }
          break;
      case /* Uident */5 :
          var longident = parseModuleLongIdent(false, p);
          return Ast_helper.Mod.ident(longident.loc, undefined, longident);
      default:
        
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(_ident, p.breadcrumbs));
  return defaultModuleExpr(undefined);
}

function parseModuleApplication(p, modExpr) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var args = parseCommaDelimitedRegion(p, /* ModExprList */41, /* Rparen */19, parseConstrainedModExprRegion);
  Res_parser.expect(undefined, /* Rparen */19, p);
  var args$1;
  if (args) {
    args$1 = args;
  } else {
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    args$1 = {
      hd: Ast_helper.Mod.structure(loc, undefined, /* [] */0),
      tl: /* [] */0
    };
  }
  return List.fold_left((function (modExpr, arg) {
                return Ast_helper.Mod.apply({
                            loc_start: modExpr.pmod_loc.loc_start,
                            loc_end: arg.pmod_loc.loc_end,
                            loc_ghost: false
                          }, undefined, modExpr, arg);
              }), modExpr, args$1);
}

function parseTemplateExpr(prefixOpt, p) {
  var prefix = prefixOpt !== undefined ? prefixOpt : "js";
  var op = $$Location.mknoloc({
        TAG: /* Lident */0,
        _0: "^"
      });
  var hiddenOperator = Ast_helper.Exp.ident(undefined, undefined, op);
  var startPos = p.startPos;
  Res_parser.nextTemplateLiteralToken(p);
  var txt = p.token;
  if (typeof txt !== "number") {
    switch (txt.TAG | 0) {
      case /* TemplateTail */7 :
          var txt$1 = txt._0;
          Res_parser.next(undefined, p);
          var txt$2 = p.mode === /* ParseForTypeChecker */0 ? parseTemplateStringLiteral(txt$1) : txt$1;
          return Ast_helper.Exp.constant({
                      loc_start: startPos,
                      loc_end: p.prevEndPos,
                      loc_ghost: false
                    }, {
                      hd: templateLiteralAttr,
                      tl: /* [] */0
                    }, {
                      TAG: /* Pconst_string */2,
                      _0: txt$2,
                      _1: prefix
                    });
      case /* TemplatePart */8 :
          var txt$3 = txt._0;
          Res_parser.next(undefined, p);
          var constantLoc_loc_end = p.prevEndPos;
          var constantLoc = {
            loc_start: startPos,
            loc_end: constantLoc_loc_end,
            loc_ghost: false
          };
          var expr = parseExprBlock(undefined, p);
          var fullLoc_loc_end = p.prevEndPos;
          var fullLoc = {
            loc_start: startPos,
            loc_end: fullLoc_loc_end,
            loc_ghost: false
          };
          var txt$4 = p.mode === /* ParseForTypeChecker */0 ? parseTemplateStringLiteral(txt$3) : txt$3;
          var str = Ast_helper.Exp.constant(constantLoc, {
                hd: templateLiteralAttr,
                tl: /* [] */0
              }, {
                TAG: /* Pconst_string */2,
                _0: txt$4,
                _1: prefix
              });
          var _acc = Ast_helper.Exp.apply(fullLoc, {
                hd: templateLiteralAttr,
                tl: /* [] */0
              }, hiddenOperator, {
                hd: [
                  /* Nolabel */0,
                  str
                ],
                tl: {
                  hd: [
                    /* Nolabel */0,
                    expr
                  ],
                  tl: /* [] */0
                }
              });
          while(true) {
            var acc = _acc;
            var startPos$1 = p.startPos;
            Res_parser.nextTemplateLiteralToken(p);
            var txt$5 = p.token;
            if (typeof txt$5 !== "number") {
              switch (txt$5.TAG | 0) {
                case /* TemplateTail */7 :
                    var txt$6 = txt$5._0;
                    Res_parser.next(undefined, p);
                    var loc_loc_end = p.prevEndPos;
                    var loc = {
                      loc_start: startPos$1,
                      loc_end: loc_loc_end,
                      loc_ghost: false
                    };
                    var txt$7 = p.mode === /* ParseForTypeChecker */0 ? parseTemplateStringLiteral(txt$6) : txt$6;
                    var str$1 = Ast_helper.Exp.constant(loc, {
                          hd: templateLiteralAttr,
                          tl: /* [] */0
                        }, {
                          TAG: /* Pconst_string */2,
                          _0: txt$7,
                          _1: prefix
                        });
                    return Ast_helper.Exp.apply(loc, {
                                hd: templateLiteralAttr,
                                tl: /* [] */0
                              }, hiddenOperator, {
                                hd: [
                                  /* Nolabel */0,
                                  acc
                                ],
                                tl: {
                                  hd: [
                                    /* Nolabel */0,
                                    str$1
                                  ],
                                  tl: /* [] */0
                                }
                              });
                case /* TemplatePart */8 :
                    var txt$8 = txt$5._0;
                    Res_parser.next(undefined, p);
                    var loc_loc_end$1 = p.prevEndPos;
                    var loc$1 = {
                      loc_start: startPos$1,
                      loc_end: loc_loc_end$1,
                      loc_ghost: false
                    };
                    var expr$1 = parseExprBlock(undefined, p);
                    var fullLoc_loc_end$1 = p.prevEndPos;
                    var fullLoc$1 = {
                      loc_start: startPos$1,
                      loc_end: fullLoc_loc_end$1,
                      loc_ghost: false
                    };
                    var txt$9 = p.mode === /* ParseForTypeChecker */0 ? parseTemplateStringLiteral(txt$8) : txt$8;
                    var str$2 = Ast_helper.Exp.constant(loc$1, {
                          hd: templateLiteralAttr,
                          tl: /* [] */0
                        }, {
                          TAG: /* Pconst_string */2,
                          _0: txt$9,
                          _1: prefix
                        });
                    var a = Ast_helper.Exp.apply(fullLoc$1, {
                          hd: templateLiteralAttr,
                          tl: /* [] */0
                        }, hiddenOperator, {
                          hd: [
                            /* Nolabel */0,
                            acc
                          ],
                          tl: {
                            hd: [
                              /* Nolabel */0,
                              str$2
                            ],
                            tl: /* [] */0
                          }
                        });
                    _acc = Ast_helper.Exp.apply(fullLoc$1, undefined, hiddenOperator, {
                          hd: [
                            /* Nolabel */0,
                            a
                          ],
                          tl: {
                            hd: [
                              /* Nolabel */0,
                              expr$1
                            ],
                            tl: /* [] */0
                          }
                        });
                    continue ;
                default:
                  
              }
            }
            Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(txt$5, p.breadcrumbs));
            return Ast_helper.Exp.constant(undefined, undefined, {
                        TAG: /* Pconst_string */2,
                        _0: "",
                        _1: undefined
                      });
          };
      default:
        
    }
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(txt, p.breadcrumbs));
  return Ast_helper.Exp.constant(undefined, undefined, {
              TAG: /* Pconst_string */2,
              _0: "",
              _1: undefined
            });
}

function parseCallExpr(p, funExpr) {
  Res_parser.expect(undefined, /* Lparen */18, p);
  var startPos = p.startPos;
  Res_parser.leaveBreadcrumb(p, /* ExprCall */11);
  var args = parseCommaDelimitedRegion(p, /* ArgumentList */45, /* Rparen */19, parseArgument);
  Res_parser.expect(undefined, /* Rparen */19, p);
  var args$1;
  if (args) {
    var match = args.hd;
    if (match[0] && typeof match[1] === "number") {
      var expr = match[2];
      var match$1 = expr.pexp_desc;
      if (typeof match$1 === "number" || match$1.TAG !== /* Pexp_construct */9) {
        args$1 = args;
      } else {
        var match$2 = match$1._0.txt;
        switch (match$2.TAG | 0) {
          case /* Lident */0 :
              args$1 = match$2._0 === "()" && !(match$1._1 !== undefined || expr.pexp_attributes || args.tl || !(!expr.pexp_loc.loc_ghost && p.mode === /* ParseForTypeChecker */0)) ? ({
                    hd: [
                      true,
                      /* Nolabel */0,
                      Ast_helper.Exp.let_(undefined, undefined, /* Nonrecursive */0, {
                            hd: Ast_helper.Vb.mk(undefined, undefined, undefined, undefined, Ast_helper.Pat.$$var(undefined, undefined, $$Location.mknoloc("__res_unit")), expr),
                            tl: /* [] */0
                          }, Ast_helper.Exp.ident(undefined, undefined, $$Location.mknoloc({
                                    TAG: /* Lident */0,
                                    _0: "__res_unit"
                                  })))
                    ],
                    tl: /* [] */0
                  }) : args;
              break;
          case /* Ldot */1 :
          case /* Lapply */2 :
              args$1 = args;
              break;
          
        }
      }
    } else {
      args$1 = args;
    }
  } else {
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    args$1 = {
      hd: [
        false,
        /* Nolabel */0,
        Ast_helper.Exp.construct(loc, undefined, $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: "()"
                }, loc), undefined)
      ],
      tl: /* [] */0
    };
  }
  var init = funExpr.pexp_loc;
  var loc_loc_start = init.loc_start;
  var loc_loc_end$1 = p.prevEndPos;
  var loc_loc_ghost = init.loc_ghost;
  var loc$1 = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end$1,
    loc_ghost: loc_loc_ghost
  };
  var args$2;
  if (args$1) {
    var match$3 = args$1.hd;
    var group = function (param, param$1) {
      var grp = param[0];
      var grp$1 = grp[1];
      var _u = grp[0];
      var expr = param$1[2];
      var lbl = param$1[1];
      var acc = param[1];
      if (param$1[0] === true) {
        return [
                [
                  true,
                  {
                    hd: [
                      lbl,
                      expr
                    ],
                    tl: /* [] */0
                  }
                ],
                {
                  hd: [
                    _u,
                    List.rev(grp$1)
                  ],
                  tl: acc
                }
              ];
      } else {
        return [
                [
                  _u,
                  {
                    hd: [
                      lbl,
                      expr
                    ],
                    tl: grp$1
                  }
                ],
                acc
              ];
      }
    };
    var match$4 = List.fold_left(group, [
          [
            match$3[0],
            {
              hd: [
                match$3[1],
                match$3[2]
              ],
              tl: /* [] */0
            }
          ],
          /* [] */0
        ], args$1.tl);
    var match$5 = match$4[0];
    args$2 = List.rev({
          hd: [
            match$5[0],
            List.rev(match$5[1])
          ],
          tl: match$4[1]
        });
  } else {
    args$2 = /* [] */0;
  }
  var apply = List.fold_left((function (callBody, group) {
          var match = processUnderscoreApplication(group[1]);
          var args = match[0];
          var tmp;
          if (group[0]) {
            var attrs = {
              hd: uncurryAttr,
              tl: /* [] */0
            };
            tmp = Ast_helper.Exp.apply(loc$1, attrs, callBody, args);
          } else {
            tmp = Ast_helper.Exp.apply(loc$1, undefined, callBody, args);
          }
          return Curry._1(match[1], tmp);
        }), funExpr, args$2);
  Res_parser.eatBreadcrumb(p);
  return apply;
}

function parseBracketAccess(p, expr, startPos) {
  Res_parser.leaveBreadcrumb(p, /* ExprArrayAccess */13);
  var lbracket = p.startPos;
  Res_parser.next(undefined, p);
  var stringStart = p.startPos;
  var s = p.token;
  if (typeof s !== "number" && s.TAG === /* String */3) {
    var s$1 = s._0;
    var s$2 = p.mode === /* ParseForTypeChecker */0 ? parseStringLiteral(s$1) : s$1;
    Res_parser.next(undefined, p);
    var stringEnd = p.prevEndPos;
    Res_parser.expect(undefined, /* Rbracket */21, p);
    Res_parser.eatBreadcrumb(p);
    var rbracket = p.prevEndPos;
    var identLoc = {
      loc_start: stringStart,
      loc_end: stringEnd,
      loc_ghost: false
    };
    var loc = {
      loc_start: startPos,
      loc_end: rbracket,
      loc_ghost: false
    };
    var e = Ast_helper.Exp.send(loc, undefined, expr, $$Location.mkloc(s$2, identLoc));
    var e$1 = parsePrimaryExpr(e, undefined, p);
    var equalStart = p.startPos;
    var match = p.token;
    if (match !== 14) {
      return e$1;
    }
    Res_parser.next(undefined, p);
    var equalEnd = p.prevEndPos;
    var rhsExpr = parseExpr(undefined, p);
    var loc_loc_end = rhsExpr.pexp_loc.loc_end;
    var loc$1 = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    var operatorLoc = {
      loc_start: equalStart,
      loc_end: equalEnd,
      loc_ghost: false
    };
    return Ast_helper.Exp.apply(loc$1, undefined, Ast_helper.Exp.ident(operatorLoc, undefined, $$Location.mkloc({
                        TAG: /* Lident */0,
                        _0: "#="
                      }, operatorLoc)), {
                hd: [
                  /* Nolabel */0,
                  e$1
                ],
                tl: {
                  hd: [
                    /* Nolabel */0,
                    rhsExpr
                  ],
                  tl: /* [] */0
                }
              });
  }
  var accessExpr = parseConstrainedOrCoercedExpr(p);
  Res_parser.expect(undefined, /* Rbracket */21, p);
  Res_parser.eatBreadcrumb(p);
  var rbracket$1 = p.prevEndPos;
  var arrayLoc = {
    loc_start: lbracket,
    loc_end: rbracket$1,
    loc_ghost: false
  };
  var match$1 = p.token;
  if (match$1 === 14) {
    Res_parser.leaveBreadcrumb(p, /* ExprArrayMutation */14);
    Res_parser.next(undefined, p);
    var rhsExpr$1 = parseExpr(undefined, p);
    var arraySet = $$Location.mkloc({
          TAG: /* Ldot */1,
          _0: {
            TAG: /* Lident */0,
            _0: "Array"
          },
          _1: "set"
        }, arrayLoc);
    var endPos = p.prevEndPos;
    var arraySet$1 = Ast_helper.Exp.apply({
          loc_start: startPos,
          loc_end: endPos,
          loc_ghost: false
        }, undefined, Ast_helper.Exp.ident(arrayLoc, undefined, arraySet), {
          hd: [
            /* Nolabel */0,
            expr
          ],
          tl: {
            hd: [
              /* Nolabel */0,
              accessExpr
            ],
            tl: {
              hd: [
                /* Nolabel */0,
                rhsExpr$1
              ],
              tl: /* [] */0
            }
          }
        });
    Res_parser.eatBreadcrumb(p);
    return arraySet$1;
  }
  var endPos$1 = p.prevEndPos;
  var e$2 = Ast_helper.Exp.apply({
        loc_start: startPos,
        loc_end: endPos$1,
        loc_ghost: false
      }, undefined, Ast_helper.Exp.ident(arrayLoc, undefined, $$Location.mkloc({
                TAG: /* Ldot */1,
                _0: {
                  TAG: /* Lident */0,
                  _0: "Array"
                },
                _1: "get"
              }, arrayLoc)), {
        hd: [
          /* Nolabel */0,
          expr
        ],
        tl: {
          hd: [
            /* Nolabel */0,
            accessExpr
          ],
          tl: /* [] */0
        }
      });
  return parsePrimaryExpr(e$2, undefined, p);
}

function parseRecordOrObjectType(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var match = p.token;
  var closedFlag = typeof match === "number" ? (
      match !== 4 ? (
          match !== 5 ? /* Closed */0 : (Res_parser.next(undefined, p), /* Open */1)
        ) : (Res_parser.next(undefined, p), /* Closed */0)
    ) : /* Closed */0;
  var match$1 = p.token;
  if (typeof match$1 !== "number" && match$1.TAG === /* Lident */4) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message(forbiddenInlineRecordDeclaration));
  }
  var startFirstField = p.startPos;
  var fields = parseCommaDelimitedRegion(p, /* StringFieldDeclarations */37, /* Rbrace */23, parseStringFieldDeclaration);
  if (fields) {
    var match$2 = fields.hd;
    if (match$2.TAG !== /* Otag */0) {
      if (fields.tl) {
        
      } else {
        Res_parser.err(startFirstField, match$2._0.ptyp_loc.loc_end, p, Res_diagnostics.message(sameTypeSpread));
      }
    }
    
  }
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Typ.object_(loc, attrs, fields, closedFlag);
}

function parseAtomicTypExpr(attrs, p) {
  Res_parser.leaveBreadcrumb(p, /* AtomicTypExpr */52);
  var startPos = p.startPos;
  var token = p.token;
  var typ;
  var exit = 0;
  if (typeof token === "number") {
    switch (token) {
      case /* Underscore */12 :
          var endPos = p.endPos;
          Res_parser.next(undefined, p);
          typ = Ast_helper.Typ.any({
                loc_start: startPos,
                loc_end: endPos,
                loc_ghost: false
              }, attrs, undefined);
          break;
      case /* SingleQuote */13 :
          Res_parser.next(undefined, p);
          var match = parseIdent(typeVar, p.startPos, p);
          typ = Ast_helper.Typ.$$var(match[1], attrs, match[0]);
          break;
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var match$1 = p.token;
          if (match$1 === 19) {
            Res_parser.next(undefined, p);
            var loc_loc_end = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var unitConstr = $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: "unit"
                }, loc);
            typ = Ast_helper.Typ.constr(undefined, attrs, unitConstr, /* [] */0);
          } else {
            var t = parseTypExpr(undefined, undefined, undefined, p);
            var match$2 = p.token;
            if (match$2 === 25) {
              Res_parser.next(undefined, p);
              typ = parseTupleType(attrs, t, startPos, p);
            } else {
              Res_parser.expect(undefined, /* Rparen */19, p);
              typ = {
                ptyp_desc: t.ptyp_desc,
                ptyp_loc: {
                  loc_start: startPos,
                  loc_end: p.prevEndPos,
                  loc_ghost: false
                },
                ptyp_attributes: List.concat({
                      hd: attrs,
                      tl: {
                        hd: t.ptyp_attributes,
                        tl: /* [] */0
                      }
                    })
              };
            }
          }
          break;
      case /* Lbracket */20 :
          typ = parsePolymorphicVariantType(attrs, p);
          break;
      case /* Lbrace */22 :
          typ = parseRecordOrObjectType(attrs, p);
          break;
      case /* Module */65 :
          Res_parser.next(undefined, p);
          Res_parser.expect(undefined, /* Lparen */18, p);
          var packageType = parsePackageType(startPos, attrs, p);
          Res_parser.expect(undefined, /* Rparen */19, p);
          typ = {
            ptyp_desc: packageType.ptyp_desc,
            ptyp_loc: {
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            },
            ptyp_attributes: packageType.ptyp_attributes
          };
          break;
      case /* Percent */77 :
          var extension = parseExtension(undefined, p);
          var loc_loc_end$1 = p.prevEndPos;
          var loc$1 = {
            loc_start: startPos,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          typ = Ast_helper.Typ.extension(loc$1, attrs, extension);
          break;
      default:
        exit = 1;
    }
  } else {
    switch (token.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 2;
          break;
      default:
        exit = 1;
    }
  }
  switch (exit) {
    case 1 :
        Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
        var match$3 = skipTokensAndMaybeRetry(p, Res_grammar.isAtomicTypExprStart);
        if (match$3 !== undefined) {
          typ = parseAtomicTypExpr(attrs, p);
        } else {
          Res_parser.err(p.prevEndPos, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
          typ = defaultType(undefined);
        }
        break;
    case 2 :
        var constr = parseValuePath(p);
        var args = parseTypeConstructorArgs(constr, p);
        typ = Ast_helper.Typ.constr({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, attrs, constr, args);
        break;
    
  }
  Res_parser.eatBreadcrumb(p);
  return typ;
}

function skipTokensAndMaybeRetry(p, isStartOfGrammar) {
  if (Res_token.isKeyword(p.token) && p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
    Res_parser.next(undefined, p);
    return ;
  }
  if (shouldAbortListParse(p)) {
    if (Curry._1(isStartOfGrammar, p.token)) {
      Res_parser.next(undefined, p);
      return Caml_option.some(undefined);
    } else {
      return ;
    }
  }
  Res_parser.next(undefined, p);
  var loop = function (p) {
    while(true) {
      if (shouldAbortListParse(p)) {
        return ;
      }
      Res_parser.next(undefined, p);
      continue ;
    };
  };
  loop(p);
  if (Curry._1(isStartOfGrammar, p.token)) {
    return Caml_option.some(undefined);
  }
  
}

function parsePolymorphicVariantType(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbracket */20, p);
  var match = p.token;
  if (typeof match === "number") {
    if (match !== 41) {
      if (match === 42) {
        Res_parser.next(undefined, p);
        Res_parser.optional(p, /* Bar */17);
        var rowField = parseTagSpecFull(p);
        var rowFields = parseTagSpecFulls(p);
        var tagNames = parseTagNames(p);
        var loc_loc_end = p.prevEndPos;
        var loc = {
          loc_start: startPos,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        var variant = Ast_helper.Typ.variant(loc, attrs, {
              hd: rowField,
              tl: rowFields
            }, /* Closed */0, tagNames);
        Res_parser.expect(undefined, /* Rbracket */21, p);
        return variant;
      }
      
    } else {
      Res_parser.next(undefined, p);
      var match$1 = p.token;
      var rowFields$1;
      var exit = 0;
      if (typeof match$1 === "number") {
        if (match$1 !== 17) {
          if (match$1 !== 21) {
            exit = 2;
          } else {
            rowFields$1 = /* [] */0;
          }
        } else {
          rowFields$1 = parseTagSpecs(p);
        }
      } else {
        exit = 2;
      }
      if (exit === 2) {
        var rowField$1 = parseTagSpec(p);
        rowFields$1 = {
          hd: rowField$1,
          tl: parseTagSpecs(p)
        };
      }
      var loc_loc_end$1 = p.prevEndPos;
      var loc$1 = {
        loc_start: startPos,
        loc_end: loc_loc_end$1,
        loc_ghost: false
      };
      var variant$1 = Ast_helper.Typ.variant(loc$1, attrs, rowFields$1, /* Open */1, undefined);
      Res_parser.expect(undefined, /* Rbracket */21, p);
      return variant$1;
    }
  }
  var rowFields1 = parseTagSpecFirst(p);
  var rowFields2 = parseTagSpecs(p);
  var loc_loc_end$2 = p.prevEndPos;
  var loc$2 = {
    loc_start: startPos,
    loc_end: loc_loc_end$2,
    loc_ghost: false
  };
  var variant$2 = Ast_helper.Typ.variant(loc$2, attrs, Pervasives.$at(rowFields1, rowFields2), /* Closed */0, undefined);
  Res_parser.expect(undefined, /* Rbracket */21, p);
  return variant$2;
}

function parseTupleType(attrs, first, startPos, p) {
  var typexprs_1 = parseCommaDelimitedRegion(p, /* TypExprList */39, /* Rparen */19, parseTypExprRegion);
  var typexprs = {
    hd: first,
    tl: typexprs_1
  };
  Res_parser.expect(undefined, /* Rparen */19, p);
  if (typexprs_1) {
    
  } else {
    Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(tupleSingleElement));
  }
  var tupleLoc_loc_end = p.prevEndPos;
  var tupleLoc = {
    loc_start: startPos,
    loc_end: tupleLoc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Typ.tuple(tupleLoc, attrs, typexprs);
}

function parseTypeParams(parent, p) {
  var opening = p.token;
  if (typeof opening !== "number") {
    return /* [] */0;
  }
  if (opening !== 18 && opening !== 42) {
    return /* [] */0;
  }
  if (p.startPos.pos_lnum !== p.prevEndPos.pos_lnum) {
    return /* [] */0;
  }
  Res_scanner.setDiamondMode(p.scanner);
  var openingStartPos = p.startPos;
  Res_parser.leaveBreadcrumb(p, /* TypeParams */30);
  Res_parser.next(undefined, p);
  var params = parseCommaDelimitedRegion(p, /* TypeParams */30, /* GreaterThan */41, parseTypeParam);
  var match = p.token;
  if (match === 19 && opening === /* Lparen */18) {
    var msg = Res_doc.toString(80, Res_doc.breakableGroup(true, Res_doc.concat({
                  hd: Res_doc.text("Type parameters require angle brackets:"),
                  tl: {
                    hd: Res_doc.indent(Res_doc.concat({
                              hd: Res_doc.line,
                              tl: {
                                hd: Res_doc.concat({
                                      hd: Res_printer.printLongident(parent.txt),
                                      tl: {
                                        hd: Res_printer.printTypeParams(params, Res_comments_table.empty),
                                        tl: /* [] */0
                                      }
                                    }),
                                tl: /* [] */0
                              }
                            })),
                    tl: /* [] */0
                  }
                })));
    Res_parser.err(openingStartPos, undefined, p, Res_diagnostics.message(msg));
    Res_parser.next(undefined, p);
  } else {
    Res_parser.expect(undefined, /* GreaterThan */41, p);
  }
  Res_scanner.popMode(p.scanner, /* Diamond */1);
  Res_parser.eatBreadcrumb(p);
  return params;
}

function parseConstructorArgs(p) {
  var lparen = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var args = parseCommaDelimitedRegion(p, /* ExprList */12, /* Rparen */19, parseConstrainedExprRegion);
  Res_parser.expect(undefined, /* Rparen */19, p);
  if (args) {
    return args;
  }
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: lparen,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return {
          hd: Ast_helper.Exp.construct(loc, undefined, $$Location.mkloc({
                    TAG: /* Lident */0,
                    _0: "()"
                  }, loc), undefined),
          tl: /* [] */0
        };
}

function parseParameters(p) {
  var startPos = p.startPos;
  var ident = p.token;
  if (typeof ident === "number") {
    switch (ident) {
      case /* Underscore */12 :
          Res_parser.next(undefined, p);
          var loc_loc_end = p.prevEndPos;
          var loc = {
            loc_start: startPos,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          return {
                  hd: {
                    TAG: /* TermParameter */0,
                    uncurried: false,
                    attrs: /* [] */0,
                    label: /* Nolabel */0,
                    expr: undefined,
                    pat: Ast_helper.Pat.any(loc, undefined, undefined),
                    pos: startPos
                  },
                  tl: /* [] */0
                };
      case /* Lparen */18 :
          Res_parser.next(undefined, p);
          var match = p.token;
          if (typeof match !== "number") {
            return parseParameterList(p);
          }
          if (match !== 4) {
            if (match !== 19) {
              return parseParameterList(p);
            }
            Res_parser.next(undefined, p);
            var loc_loc_end$1 = p.prevEndPos;
            var loc$1 = {
              loc_start: startPos,
              loc_end: loc_loc_end$1,
              loc_ghost: false
            };
            var unitPattern = Ast_helper.Pat.construct(loc$1, undefined, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: "()"
                    }, loc$1), undefined);
            return {
                    hd: {
                      TAG: /* TermParameter */0,
                      uncurried: false,
                      attrs: /* [] */0,
                      label: /* Nolabel */0,
                      expr: undefined,
                      pat: unitPattern,
                      pos: startPos
                    },
                    tl: /* [] */0
                  };
          }
          Res_parser.next(undefined, p);
          var match$1 = p.token;
          if (match$1 === 19) {
            Res_parser.next(undefined, p);
            var loc_loc_end$2 = p.prevEndPos;
            var loc$2 = {
              loc_start: startPos,
              loc_end: loc_loc_end$2,
              loc_ghost: false
            };
            var unitPattern$1 = Ast_helper.Pat.construct(loc$2, undefined, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: "()"
                    }, loc$2), undefined);
            return {
                    hd: {
                      TAG: /* TermParameter */0,
                      uncurried: true,
                      attrs: /* [] */0,
                      label: /* Nolabel */0,
                      expr: undefined,
                      pat: unitPattern$1,
                      pos: startPos
                    },
                    tl: /* [] */0
                  };
          }
          var parameters = parseParameterList(p);
          if (!parameters) {
            return parameters;
          }
          var match$2 = parameters.hd;
          if (match$2.TAG === /* TermParameter */0) {
            return {
                    hd: {
                      TAG: /* TermParameter */0,
                      uncurried: true,
                      attrs: match$2.attrs,
                      label: match$2.label,
                      expr: match$2.expr,
                      pat: match$2.pat,
                      pos: match$2.pos
                    },
                    tl: parameters.tl
                  };
          } else {
            return parameters;
          }
      default:
        
    }
  } else if (ident.TAG === /* Lident */4) {
    Res_parser.next(undefined, p);
    var loc_loc_end$3 = p.prevEndPos;
    var loc$3 = {
      loc_start: startPos,
      loc_end: loc_loc_end$3,
      loc_ghost: false
    };
    return {
            hd: {
              TAG: /* TermParameter */0,
              uncurried: false,
              attrs: /* [] */0,
              label: /* Nolabel */0,
              expr: undefined,
              pat: Ast_helper.Pat.$$var(loc$3, undefined, $$Location.mkloc(ident._0, loc$3)),
              pos: startPos
            },
            tl: /* [] */0
          };
  }
  Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(ident, p.breadcrumbs));
  return /* [] */0;
}

function parseSignLetDesc(attrs, p) {
  var startPos = p.startPos;
  Res_parser.optional(p, /* Let */9);
  var match = parseLident(p);
  var name = $$Location.mkloc(match[0], match[1]);
  Res_parser.expect(undefined, /* Colon */24, p);
  var typExpr = parsePolyTypeExpr(p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Val.mk(loc, attrs, undefined, undefined, name, typExpr);
}

function parseCoercedExpr(expr, p) {
  Res_parser.expect(undefined, /* ColonGreaterThan */40, p);
  var typ = parseTypExpr(undefined, undefined, undefined, p);
  var loc_loc_start = expr.pexp_loc.loc_start;
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.coerce(loc, undefined, expr, undefined, typ);
}

function parseMaybeRecModuleBinding(attrs, startPos, p) {
  var match = p.token;
  if (match === 11) {
    Res_parser.next(undefined, p);
    return Ast_helper.Str.rec_module(undefined, parseModuleBindings(attrs, startPos, p));
  } else {
    return Ast_helper.Str.module_(undefined, parseModuleBinding(attrs, p.startPos, p));
  }
}

function parseModuleTypeImpl(attrs, startPos, p) {
  Res_parser.expect(undefined, /* Typ */60, p);
  var nameStart = p.startPos;
  var ident = p.token;
  var name;
  var exit = 0;
  if (typeof ident === "number") {
    exit = 2;
  } else {
    switch (ident.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 1;
          break;
      default:
        exit = 2;
    }
  }
  switch (exit) {
    case 1 :
        Res_parser.next(undefined, p);
        var loc_loc_end = p.prevEndPos;
        var loc = {
          loc_start: nameStart,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        name = $$Location.mkloc(ident._0, loc);
        break;
    case 2 :
        Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
        name = $$Location.mknoloc("_");
        break;
    
  }
  Res_parser.expect(undefined, /* Equal */14, p);
  var moduleType = parseModuleType(undefined, undefined, p);
  var moduleTypeDeclaration = Ast_helper.Mtd.mk({
        loc_start: nameStart,
        loc_end: p.prevEndPos,
        loc_ghost: false
      }, attrs, undefined, undefined, moduleType, name);
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Str.modtype(loc$1, moduleTypeDeclaration);
}

function parseIfCondition(p) {
  Res_parser.leaveBreadcrumb(p, /* IfCondition */17);
  var conditionExpr = parseExpr(/* WhenExpr */2, p);
  Res_parser.eatBreadcrumb(p);
  return conditionExpr;
}

function parseIfOrIfLetExpression(p) {
  Res_parser.beginRegion(p);
  Res_parser.leaveBreadcrumb(p, /* ExprIf */15);
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* If */50, p);
  var match = p.token;
  var expr;
  if (match === 9) {
    Res_parser.next(undefined, p);
    var ifLetExpr = parseIfLetExpr(startPos, p);
    Res_parser.err(ifLetExpr.pexp_loc.loc_start, ifLetExpr.pexp_loc.loc_end, p, Res_diagnostics.message(experimentalIfLet(ifLetExpr)));
    expr = ifLetExpr;
  } else {
    expr = parseIfExpr(startPos, p);
  }
  Res_parser.eatBreadcrumb(p);
  return expr;
}

function parseElseBranch(p) {
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var blockExpr = parseExprBlock(undefined, p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  return blockExpr;
}

function parseThenBranch(p) {
  Res_parser.leaveBreadcrumb(p, /* IfBranch */18);
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var thenExpr = parseExprBlock(undefined, p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  Res_parser.eatBreadcrumb(p);
  return thenExpr;
}

function parseRecordRowWithStringKey(p) {
  var s = p.token;
  if (typeof s === "number") {
    return ;
  }
  if (s.TAG !== /* String */3) {
    return ;
  }
  var loc_loc_start = p.startPos;
  var loc_loc_end = p.endPos;
  var loc = {
    loc_start: loc_loc_start,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  Res_parser.next(undefined, p);
  var field = $$Location.mkloc({
        TAG: /* Lident */0,
        _0: s._0
      }, loc);
  var match = p.token;
  if (match !== 24) {
    return [
            field,
            Ast_helper.Exp.ident(field.loc, undefined, field)
          ];
  }
  Res_parser.next(undefined, p);
  var fieldExpr = parseExpr(undefined, p);
  return [
          field,
          fieldExpr
        ];
}

function parseModuleTypeOf(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Module */65, p);
  Res_parser.expect(undefined, /* Typ */60, p);
  Res_parser.expect(undefined, /* Of */66, p);
  var moduleExpr = parseModuleExpr(p);
  return Ast_helper.Mty.typeof_({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, undefined, moduleExpr);
}

function parseParameter(p) {
  if (!(p.token === /* Typ */60 || p.token === /* Tilde */48 || p.token === /* Dot */4 || Res_grammar.isPatternStart(p.token))) {
    return ;
  }
  var startPos = p.startPos;
  var uncurried = Res_parser.optional(p, /* Dot */4);
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  if (p.token === /* Typ */60) {
    Res_parser.next(undefined, p);
    var lidents = parseLidentList(p);
    return {
            TAG: /* TypeParameter */1,
            uncurried: uncurried,
            attrs: attrs,
            locs: lidents,
            pos: startPos
          };
  }
  var match = p.token;
  var match$1;
  if (match === 48) {
    Res_parser.next(undefined, p);
    var match$2 = parseLident(p);
    var lblName = match$2[0];
    var propLocAttr_0 = $$Location.mkloc("ns.namedArgLoc", match$2[1]);
    var propLocAttr_1 = {
      TAG: /* PStr */0,
      _0: /* [] */0
    };
    var propLocAttr = [
      propLocAttr_0,
      propLocAttr_1
    ];
    var t = p.token;
    var exit = 0;
    if (typeof t === "number" && t < 26) {
      switch (t) {
        case /* As */3 :
            Res_parser.next(undefined, p);
            var pat = parseConstrainedPattern(p);
            var pat_ppat_desc = pat.ppat_desc;
            var pat_ppat_loc = pat.ppat_loc;
            var pat_ppat_attributes = {
              hd: propLocAttr,
              tl: pat.ppat_attributes
            };
            var pat$1 = {
              ppat_desc: pat_ppat_desc,
              ppat_loc: pat_ppat_loc,
              ppat_attributes: pat_ppat_attributes
            };
            match$1 = [
              attrs,
              {
                TAG: /* Labelled */0,
                _0: lblName
              },
              pat$1
            ];
            break;
        case /* Open */0 :
        case /* True */1 :
        case /* False */2 :
        case /* Dot */4 :
        case /* DotDot */5 :
        case /* DotDotDot */6 :
        case /* Bang */7 :
        case /* Semicolon */8 :
        case /* Let */9 :
        case /* And */10 :
        case /* Rec */11 :
        case /* Underscore */12 :
        case /* SingleQuote */13 :
        case /* EqualEqual */15 :
        case /* EqualEqualEqual */16 :
        case /* Bar */17 :
        case /* Lparen */18 :
        case /* Lbracket */20 :
        case /* Rbracket */21 :
        case /* Lbrace */22 :
        case /* Rbrace */23 :
            exit = 1;
            break;
        case /* Colon */24 :
            var lblEnd = p.prevEndPos;
            Res_parser.next(undefined, p);
            var typ = parseTypExpr(undefined, undefined, undefined, p);
            var loc = {
              loc_start: startPos,
              loc_end: lblEnd,
              loc_ghost: false
            };
            var pat$2 = Ast_helper.Pat.$$var(loc, undefined, $$Location.mkloc(lblName, loc));
            var loc_loc_end = p.prevEndPos;
            var loc$1 = {
              loc_start: startPos,
              loc_end: loc_loc_end,
              loc_ghost: false
            };
            var pat$3 = Ast_helper.Pat.constraint_(loc$1, {
                  hd: propLocAttr,
                  tl: /* [] */0
                }, pat$2, typ);
            match$1 = [
              attrs,
              {
                TAG: /* Labelled */0,
                _0: lblName
              },
              pat$3
            ];
            break;
        case /* Equal */14 :
        case /* Rparen */19 :
        case /* Comma */25 :
            exit = 2;
            break;
        
      }
    } else {
      exit = 1;
    }
    switch (exit) {
      case 1 :
          Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(t, p.breadcrumbs));
          var loc_loc_end$1 = p.prevEndPos;
          var loc$2 = {
            loc_start: startPos,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          match$1 = [
            attrs,
            {
              TAG: /* Labelled */0,
              _0: lblName
            },
            Ast_helper.Pat.$$var(loc$2, undefined, $$Location.mkloc(lblName, loc$2))
          ];
          break;
      case 2 :
          var loc_loc_end$2 = p.prevEndPos;
          var loc$3 = {
            loc_start: startPos,
            loc_end: loc_loc_end$2,
            loc_ghost: false
          };
          match$1 = [
            attrs,
            {
              TAG: /* Labelled */0,
              _0: lblName
            },
            Ast_helper.Pat.$$var(loc$3, {
                  hd: propLocAttr,
                  tl: /* [] */0
                }, $$Location.mkloc(lblName, loc$3))
          ];
          break;
      
    }
  } else {
    var pattern = parseConstrainedPattern(p);
    var attrs$1 = List.concat({
          hd: attrs,
          tl: {
            hd: pattern.ppat_attributes,
            tl: /* [] */0
          }
        });
    match$1 = [
      /* [] */0,
      /* Nolabel */0,
      {
        ppat_desc: pattern.ppat_desc,
        ppat_loc: pattern.ppat_loc,
        ppat_attributes: attrs$1
      }
    ];
  }
  var pat$4 = match$1[2];
  var lbl = match$1[1];
  var attrs$2 = match$1[0];
  var match$3 = p.token;
  if (match$3 !== 14) {
    return {
            TAG: /* TermParameter */0,
            uncurried: uncurried,
            attrs: attrs$2,
            label: lbl,
            expr: undefined,
            pat: pat$4,
            pos: startPos
          };
  }
  Res_parser.next(undefined, p);
  var lbl$1;
  if (typeof lbl === "number") {
    var $$var = pat$4.ppat_desc;
    var lblName$1;
    lblName$1 = typeof $$var === "number" || $$var.TAG !== /* Ppat_var */0 ? "" : $$var._0.txt;
    Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(missingTildeLabeledParameter(lblName$1)));
    lbl$1 = {
      TAG: /* Optional */1,
      _0: lblName$1
    };
  } else {
    lbl$1 = lbl.TAG === /* Labelled */0 ? ({
          TAG: /* Optional */1,
          _0: lbl._0
        }) : lbl;
  }
  var match$4 = p.token;
  if (match$4 === 49) {
    Res_parser.next(undefined, p);
    return {
            TAG: /* TermParameter */0,
            uncurried: uncurried,
            attrs: attrs$2,
            label: lbl$1,
            expr: undefined,
            pat: pat$4,
            pos: startPos
          };
  }
  var expr = parseConstrainedOrCoercedExpr(p);
  return {
          TAG: /* TermParameter */0,
          uncurried: uncurried,
          attrs: attrs$2,
          label: lbl$1,
          expr: expr,
          pat: pat$4,
          pos: startPos
        };
}

function parseExprBlockItem(p) {
  var startPos = p.startPos;
  var attrs = parseRegion(p, /* Attribute */50, parseAttribute);
  var match = p.token;
  if (typeof match === "number") {
    if (match >= 27) {
      if (match !== 65) {
        if (match < 28) {
          var extensionConstructor = parseExceptionDef(attrs, p);
          parseNewlineOrSemicolonExprBlock(p);
          var blockExpr = parseExprBlock(undefined, p);
          var loc_loc_end = p.prevEndPos;
          var loc = {
            loc_start: startPos,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          return Ast_helper.Exp.letexception(loc, undefined, extensionConstructor, blockExpr);
        }
        
      } else {
        Res_parser.next(undefined, p);
        var match$1 = p.token;
        if (match$1 === 18) {
          var expr = parseFirstClassModuleExpr(startPos, p);
          var a = parsePrimaryExpr(expr, undefined, p);
          var expr$1 = parseBinaryExpr(undefined, a, p, 1);
          return parseTernaryExpr(expr$1, p);
        }
        var ident = p.token;
        var name;
        var exit = 0;
        if (typeof ident === "number" || ident.TAG !== /* Uident */5) {
          exit = 2;
        } else {
          var loc_loc_start = p.startPos;
          var loc_loc_end$1 = p.endPos;
          var loc$1 = {
            loc_start: loc_loc_start,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          Res_parser.next(undefined, p);
          name = $$Location.mkloc(ident._0, loc$1);
        }
        if (exit === 2) {
          Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
          name = $$Location.mknoloc("_");
        }
        var body = parseModuleBindingBody(p);
        parseNewlineOrSemicolonExprBlock(p);
        var expr$2 = parseExprBlock(undefined, p);
        var loc_loc_end$2 = p.prevEndPos;
        var loc$2 = {
          loc_start: startPos,
          loc_end: loc_loc_end$2,
          loc_ghost: false
        };
        return Ast_helper.Exp.letmodule(loc$2, undefined, name, body, expr$2);
      }
    } else if (match !== 9) {
      if (match === 0) {
        var od = parseOpenDescription(attrs, p);
        parseNewlineOrSemicolonExprBlock(p);
        var blockExpr$1 = parseExprBlock(undefined, p);
        var loc_loc_end$3 = p.prevEndPos;
        var loc$3 = {
          loc_start: startPos,
          loc_end: loc_loc_end$3,
          loc_ghost: false
        };
        return Ast_helper.Exp.open_(loc$3, undefined, od.popen_override, od.popen_lid, blockExpr$1);
      }
      
    } else {
      var match$2 = parseLetBindings(attrs, p);
      parseNewlineOrSemicolonExprBlock(p);
      var next;
      if (Res_grammar.isBlockExprStart(p.token)) {
        next = parseExprBlock(undefined, p);
      } else {
        var loc_loc_start$1 = p.startPos;
        var loc_loc_end$4 = p.endPos;
        var loc$4 = {
          loc_start: loc_loc_start$1,
          loc_end: loc_loc_end$4,
          loc_ghost: false
        };
        next = Ast_helper.Exp.construct(loc$4, undefined, $$Location.mkloc({
                  TAG: /* Lident */0,
                  _0: "()"
                }, loc$4), undefined);
      }
      var loc_loc_end$5 = p.prevEndPos;
      var loc$5 = {
        loc_start: startPos,
        loc_end: loc_loc_end$5,
        loc_ghost: false
      };
      return Ast_helper.Exp.let_(loc$5, undefined, match$2[0], match$2[1], next);
    }
  }
  var expr$3 = parseExpr(undefined, p);
  var e1_pexp_desc = expr$3.pexp_desc;
  var e1_pexp_loc = expr$3.pexp_loc;
  var e1_pexp_attributes = List.concat({
        hd: attrs,
        tl: {
          hd: expr$3.pexp_attributes,
          tl: /* [] */0
        }
      });
  var e1 = {
    pexp_desc: e1_pexp_desc,
    pexp_loc: e1_pexp_loc,
    pexp_attributes: e1_pexp_attributes
  };
  parseNewlineOrSemicolonExprBlock(p);
  if (!Res_grammar.isBlockExprStart(p.token)) {
    return e1;
  }
  var e2 = parseExprBlock(undefined, p);
  var init = e1_pexp_loc;
  var loc_loc_start$2 = init.loc_start;
  var loc_loc_end$6 = e2.pexp_loc.loc_end;
  var loc_loc_ghost = init.loc_ghost;
  var loc$6 = {
    loc_start: loc_loc_start$2,
    loc_end: loc_loc_end$6,
    loc_ghost: loc_loc_ghost
  };
  return Ast_helper.Exp.sequence(loc$6, undefined, e1, e2);
}

function parseJsxName(p) {
  var ident = p.token;
  var longident;
  var exit = 0;
  if (typeof ident === "number") {
    exit = 1;
  } else {
    switch (ident.TAG | 0) {
      case /* Lident */4 :
          var identStart = p.startPos;
          var identEnd = p.endPos;
          Res_parser.next(undefined, p);
          var loc = {
            loc_start: identStart,
            loc_end: identEnd,
            loc_ghost: false
          };
          longident = $$Location.mkloc({
                TAG: /* Lident */0,
                _0: ident._0
              }, loc);
          break;
      case /* Uident */5 :
          var longident$1 = parseModuleLongIdent(true, p);
          longident = $$Location.mkloc({
                TAG: /* Ldot */1,
                _0: longident$1.txt,
                _1: "createElement"
              }, longident$1.loc);
          break;
      default:
        exit = 1;
    }
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.message("A jsx name must be a lowercase or uppercase name, like: div in <div /> or Navbar in <Navbar />"));
    longident = $$Location.mknoloc({
          TAG: /* Lident */0,
          _0: "_"
        });
  }
  return Ast_helper.Exp.ident(longident.loc, undefined, longident);
}

function parseJsxOpeningOrSelfClosingElement(startPos, p) {
  var jsxStartPos = p.startPos;
  var name = parseJsxName(p);
  var jsxProps = parseRegion(p, /* JsxAttribute */5, parseJsxProp);
  var token = p.token;
  var children;
  var exit = 0;
  if (typeof token === "number") {
    if (token !== 29) {
      if (token !== 41) {
        exit = 1;
      } else {
        var childrenStartPos = p.startPos;
        Res_scanner.setJsxMode(p.scanner);
        Res_parser.next(undefined, p);
        var match = parseJsxChildren(p);
        var children$1 = match[1];
        var spread = match[0];
        var childrenEndPos = p.startPos;
        var token$1 = p.token;
        var exit$1 = 0;
        if (typeof token$1 === "number") {
          if (token$1 !== 42) {
            if (token$1 !== 43) {
              exit$1 = 2;
            } else {
              Res_parser.next(undefined, p);
            }
          } else {
            Res_parser.next(undefined, p);
            Res_parser.expect(undefined, /* Forwardslash */29, p);
          }
        } else {
          exit$1 = 2;
        }
        if (exit$1 === 2) {
          if (Res_grammar.isStructureItemStart(token$1)) {
            
          } else {
            Res_parser.expect(undefined, /* LessThanSlash */43, p);
          }
        }
        var token$2 = p.token;
        var exit$2 = 0;
        var exit$3 = 0;
        if (typeof token$2 === "number") {
          exit$2 = 2;
        } else {
          switch (token$2.TAG | 0) {
            case /* Lident */4 :
            case /* Uident */5 :
                exit$3 = 3;
                break;
            default:
              exit$2 = 2;
          }
        }
        if (exit$3 === 3) {
          if (verifyJsxOpeningClosingName(p, name)) {
            Res_parser.expect(undefined, /* GreaterThan */41, p);
            var loc = {
              loc_start: childrenStartPos,
              loc_end: childrenEndPos,
              loc_ghost: false
            };
            children = spread && children$1 ? children$1.hd : makeListExpression(loc, children$1, undefined);
          } else {
            exit$2 = 2;
          }
        }
        if (exit$2 === 2) {
          if (Res_grammar.isStructureItemStart(token$2)) {
            var closing = "</" + (string_of_pexp_ident(name) + ">");
            var msg = Res_diagnostics.message("Missing " + closing);
            Res_parser.err(startPos, p.prevEndPos, p, msg);
          } else {
            var opening = "</" + (string_of_pexp_ident(name) + ">");
            var msg$1 = "Closing jsx name should be the same as the opening name. Did you mean " + (opening + " ?");
            Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(msg$1));
            Res_parser.expect(undefined, /* GreaterThan */41, p);
          }
          var loc$1 = {
            loc_start: childrenStartPos,
            loc_end: childrenEndPos,
            loc_ghost: false
          };
          children = spread && children$1 ? children$1.hd : makeListExpression(loc$1, children$1, undefined);
        }
        
      }
    } else {
      var childrenStartPos$1 = p.startPos;
      Res_parser.next(undefined, p);
      var childrenEndPos$1 = p.startPos;
      Res_parser.expect(undefined, /* GreaterThan */41, p);
      var loc$2 = {
        loc_start: childrenStartPos$1,
        loc_end: childrenEndPos$1,
        loc_ghost: false
      };
      children = makeListExpression(loc$2, /* [] */0, undefined);
    }
  } else {
    exit = 1;
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
    children = makeListExpression($$Location.none, /* [] */0, undefined);
  }
  var jsxEndPos = p.prevEndPos;
  var loc$3 = {
    loc_start: jsxStartPos,
    loc_end: jsxEndPos,
    loc_ghost: false
  };
  return Ast_helper.Exp.apply(loc$3, undefined, name, List.concat({
                  hd: jsxProps,
                  tl: {
                    hd: {
                      hd: [
                        {
                          TAG: /* Labelled */0,
                          _0: "children"
                        },
                        children
                      ],
                      tl: {
                        hd: [
                          /* Nolabel */0,
                          Ast_helper.Exp.construct(undefined, undefined, $$Location.mknoloc({
                                    TAG: /* Lident */0,
                                    _0: "()"
                                  }), undefined)
                        ],
                        tl: /* [] */0
                      }
                    },
                    tl: /* [] */0
                  }
                }));
}

function parseJsxFragment(p) {
  var childrenStartPos = p.startPos;
  Res_scanner.setJsxMode(p.scanner);
  Res_parser.expect(undefined, /* GreaterThan */41, p);
  var match = parseJsxChildren(p);
  var childrenEndPos = p.startPos;
  Res_parser.expect(undefined, /* LessThanSlash */43, p);
  Res_parser.expect(undefined, /* GreaterThan */41, p);
  var loc = {
    loc_start: childrenStartPos,
    loc_end: childrenEndPos,
    loc_ghost: false
  };
  return makeListExpression(loc, match[1], undefined);
}

function parseTypeConstructorDeclarationWithBar(p) {
  var match = p.token;
  if (match !== 17) {
    return ;
  }
  var startPos = p.startPos;
  Res_parser.next(undefined, p);
  return parseTypeConstructorDeclaration(startPos, p);
}

function parsePatternMatching(p) {
  var cases = parseDelimitedRegion(p, /* PatternMatching */22, /* Rbrace */23, parsePatternMatchCase);
  if (cases) {
    
  } else {
    Res_parser.err(p.prevEndPos, undefined, p, Res_diagnostics.message("Pattern matching needs at least one case"));
  }
  return cases;
}

function parseJsxProp(p) {
  var match = p.token;
  if (typeof match === "number") {
    if (match !== /* Question */49) {
      return ;
    }
    
  } else if (match.TAG !== /* Lident */4) {
    return ;
  }
  var optional = Res_parser.optional(p, /* Question */49);
  var match$1 = parseLident(p);
  var loc = match$1[1];
  var name = match$1[0];
  var propLocAttr_0 = $$Location.mkloc("ns.namedArgLoc", loc);
  var propLocAttr_1 = {
    TAG: /* PStr */0,
    _0: /* [] */0
  };
  var propLocAttr = [
    propLocAttr_0,
    propLocAttr_1
  ];
  if (optional) {
    return [
            {
              TAG: /* Optional */1,
              _0: name
            },
            Ast_helper.Exp.ident(loc, {
                  hd: propLocAttr,
                  tl: /* [] */0
                }, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: name
                    }, loc))
          ];
  }
  var match$2 = p.token;
  if (match$2 === 14) {
    Res_parser.next(undefined, p);
    var optional$1 = Res_parser.optional(p, /* Question */49);
    var e = parsePrimaryExpr(parseAtomicExpr(p), undefined, p);
    var attrExpr_pexp_desc = e.pexp_desc;
    var attrExpr_pexp_loc = e.pexp_loc;
    var attrExpr_pexp_attributes = {
      hd: propLocAttr,
      tl: e.pexp_attributes
    };
    var attrExpr = {
      pexp_desc: attrExpr_pexp_desc,
      pexp_loc: attrExpr_pexp_loc,
      pexp_attributes: attrExpr_pexp_attributes
    };
    var label = optional$1 ? ({
          TAG: /* Optional */1,
          _0: name
        }) : ({
          TAG: /* Labelled */0,
          _0: name
        });
    return [
            label,
            attrExpr
          ];
  }
  var attrExpr$1 = Ast_helper.Exp.ident(loc, {
        hd: propLocAttr,
        tl: /* [] */0
      }, $$Location.mkloc({
            TAG: /* Lident */0,
            _0: name
          }, loc));
  var label$1 = optional ? ({
        TAG: /* Optional */1,
        _0: name
      }) : ({
        TAG: /* Labelled */0,
        _0: name
      });
  return [
          label$1,
          attrExpr$1
        ];
}

function parseTypeConstructorArgRegion(p) {
  while(true) {
    if (Res_grammar.isTypExprStart(p.token)) {
      return parseTypExpr(undefined, undefined, undefined, p);
    }
    if (p.token !== /* LessThan */42) {
      return ;
    }
    Res_parser.next(undefined, p);
    continue ;
  };
}

function parseModuleTypeDeclaration(attrs, startPos, p) {
  Res_parser.expect(undefined, /* Typ */60, p);
  var ident = p.token;
  var moduleName;
  var exit = 0;
  if (typeof ident === "number") {
    exit = 2;
  } else {
    switch (ident.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 1;
          break;
      default:
        exit = 2;
    }
  }
  switch (exit) {
    case 1 :
        var loc_loc_start = p.startPos;
        var loc_loc_end = p.endPos;
        var loc = {
          loc_start: loc_loc_start,
          loc_end: loc_loc_end,
          loc_ghost: false
        };
        Res_parser.next(undefined, p);
        moduleName = $$Location.mkloc(ident._0, loc);
        break;
    case 2 :
        Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
        moduleName = $$Location.mknoloc("_");
        break;
    
  }
  var match = p.token;
  var typ = match === 14 ? (Res_parser.next(undefined, p), parseModuleType(undefined, undefined, p)) : undefined;
  var moduleDecl = Ast_helper.Mtd.mk(undefined, attrs, undefined, undefined, typ, moduleName);
  return Ast_helper.Sig.modtype({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, moduleDecl);
}

function parseNewlineOrSemicolonSignature(p) {
  var token = p.token;
  if (token === 8) {
    return Res_parser.next(undefined, p);
  } else if (Res_grammar.isSignatureItemStart(token) && p.prevEndPos.pos_lnum >= p.startPos.pos_lnum) {
    return Res_parser.err(p.prevEndPos, p.endPos, p, Res_diagnostics.message("consecutive specifications on a line must be separated by ';' or a newline"));
  } else {
    return ;
  }
}

function parseModuleDeclarationOrAlias(attrs, p) {
  var startPos = p.startPos;
  var ident = p.token;
  var moduleName;
  var exit = 0;
  if (typeof ident === "number" || ident.TAG !== /* Uident */5) {
    exit = 1;
  } else {
    var loc_loc_start = p.startPos;
    var loc_loc_end = p.endPos;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    moduleName = $$Location.mkloc(ident._0, loc);
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.uident(ident));
    moduleName = $$Location.mknoloc("_");
  }
  var token = p.token;
  var body;
  var exit$1 = 0;
  if (typeof token === "number") {
    if (token !== 14) {
      if (token !== 24) {
        exit$1 = 1;
      } else {
        Res_parser.next(undefined, p);
        body = parseModuleType(undefined, undefined, p);
      }
    } else {
      Res_parser.next(undefined, p);
      var lident = parseModuleLongIdent(false, p);
      body = Ast_helper.Mty.alias(undefined, undefined, lident);
    }
  } else {
    exit$1 = 1;
  }
  if (exit$1 === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
    body = defaultModuleType(undefined);
  }
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Md.mk(loc$1, attrs, undefined, undefined, moduleName, body);
}

function parseSignJsExport(attrs, p) {
  var exportStart = p.startPos;
  Res_parser.expect(undefined, /* Export */84, p);
  var exportLoc_loc_end = p.prevEndPos;
  var exportLoc = {
    loc_start: exportStart,
    loc_end: exportLoc_loc_end,
    loc_ghost: false
  };
  var genTypeAttr_0 = $$Location.mkloc("genType", exportLoc);
  var genTypeAttr_1 = {
    TAG: /* PStr */0,
    _0: /* [] */0
  };
  var genTypeAttr = [
    genTypeAttr_0,
    genTypeAttr_1
  ];
  var attrs$1 = {
    hd: genTypeAttr,
    tl: attrs
  };
  var match = p.token;
  if (match === 60) {
    var ext = parseTypeDefinitionOrExtension(attrs$1, p);
    if (ext.TAG === /* TypeDef */0) {
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: exportStart,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      return Ast_helper.Sig.type_(loc, ext.recFlag, ext.types);
    }
    var loc_loc_end$1 = p.prevEndPos;
    var loc$1 = {
      loc_start: exportStart,
      loc_end: loc_loc_end$1,
      loc_ghost: false
    };
    return Ast_helper.Sig.type_extension(loc$1, ext._0);
  }
  var valueDesc = parseSignLetDesc(attrs$1, p);
  var loc_loc_end$2 = p.prevEndPos;
  var loc$2 = {
    loc_start: exportStart,
    loc_end: loc_loc_end$2,
    loc_ghost: false
  };
  return Ast_helper.Sig.value(loc$2, valueDesc);
}

function parseRecModuleSpec(attrs, startPos, p) {
  Res_parser.expect(undefined, /* Rec */11, p);
  var first = parseRecModuleDeclaration(attrs, startPos, p);
  var _spec = {
    hd: first,
    tl: /* [] */0
  };
  while(true) {
    var spec = _spec;
    var startPos$1 = p.startPos;
    var attrs$1 = parseAttributesAndBinding(p);
    var match = p.token;
    if (match !== 10) {
      return List.rev(spec);
    }
    Res_parser.expect(undefined, /* And */10, p);
    var decl = parseRecModuleDeclaration(attrs$1, startPos$1, p);
    _spec = {
      hd: decl,
      tl: spec
    };
    continue ;
  };
}

function parseEs6ArrowType(attrs, p) {
  var startPos = p.startPos;
  var match = p.token;
  if (match === 48) {
    Res_parser.next(undefined, p);
    var match$1 = parseLident(p);
    var name = match$1[0];
    var lblLocAttr_0 = $$Location.mkloc("ns.namedArgLoc", match$1[1]);
    var lblLocAttr_1 = {
      TAG: /* PStr */0,
      _0: /* [] */0
    };
    var lblLocAttr = [
      lblLocAttr_0,
      lblLocAttr_1
    ];
    Res_parser.expect(/* TypeExpression */20, /* Colon */24, p);
    var typ = parseTypExpr(undefined, false, false, p);
    var typ_ptyp_desc = typ.ptyp_desc;
    var typ_ptyp_loc = typ.ptyp_loc;
    var typ_ptyp_attributes = {
      hd: lblLocAttr,
      tl: typ.ptyp_attributes
    };
    var typ$1 = {
      ptyp_desc: typ_ptyp_desc,
      ptyp_loc: typ_ptyp_loc,
      ptyp_attributes: typ_ptyp_attributes
    };
    var match$2 = p.token;
    var arg = match$2 === 14 ? (Res_parser.next(undefined, p), Res_parser.expect(undefined, /* Question */49, p), {
          TAG: /* Optional */1,
          _0: name
        }) : ({
          TAG: /* Labelled */0,
          _0: name
        });
    Res_parser.expect(undefined, /* EqualGreater */57, p);
    var returnType = parseTypExpr(undefined, undefined, false, p);
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return Ast_helper.Typ.arrow(loc, attrs, arg, typ$1, returnType);
  }
  var parameters = parseTypeParameters(p);
  Res_parser.expect(undefined, /* EqualGreater */57, p);
  var returnType$1 = parseTypExpr(undefined, undefined, false, p);
  var endPos = p.prevEndPos;
  var typ$2 = List.fold_right((function (param, t) {
          var attrs = param[1];
          var attrs$1 = param[0] ? ({
                hd: uncurryAttr,
                tl: attrs
              }) : attrs;
          return Ast_helper.Typ.arrow({
                      loc_start: param[4],
                      loc_end: endPos,
                      loc_ghost: false
                    }, attrs$1, param[2], param[3], t);
        }), parameters, returnType$1);
  return {
          ptyp_desc: typ$2.ptyp_desc,
          ptyp_loc: {
            loc_start: startPos,
            loc_end: p.prevEndPos,
            loc_ghost: false
          },
          ptyp_attributes: List.concat({
                hd: typ$2.ptyp_attributes,
                tl: {
                  hd: attrs,
                  tl: /* [] */0
                }
              })
        };
}

function parseJsxChildren(p) {
  var loop = function (p, _children) {
    while(true) {
      var children = _children;
      var token = p.token;
      if (typeof token === "number") {
        if (token === 43 || token === 42) {
          if (token >= 43) {
            Res_scanner.popMode(p.scanner, /* Jsx */0);
            return List.rev(children);
          }
          var token$1 = Res_scanner.reconsiderLessThan(p.scanner);
          if (token$1 === /* LessThan */42) {
            var child = parsePrimaryExpr(parseAtomicExpr(p), true, p);
            _children = {
              hd: child,
              tl: children
            };
            continue ;
          }
          p.token = token$1;
          Res_scanner.popMode(p.scanner, /* Jsx */0);
          return List.rev(children);
        }
        if (token === 26) {
          Res_scanner.popMode(p.scanner, /* Jsx */0);
          return List.rev(children);
        }
        
      }
      if (Res_grammar.isJsxChildStart(token)) {
        Res_scanner.popMode(p.scanner, /* Jsx */0);
        var child$1 = parsePrimaryExpr(parseAtomicExpr(p), true, p);
        _children = {
          hd: child$1,
          tl: children
        };
        continue ;
      }
      Res_scanner.popMode(p.scanner, /* Jsx */0);
      return List.rev(children);
    };
  };
  var match = p.token;
  if (match === 6) {
    Res_parser.next(undefined, p);
    return [
            true,
            {
              hd: parsePrimaryExpr(parseAtomicExpr(p), true, p),
              tl: /* [] */0
            }
          ];
  } else {
    return [
            false,
            loop(p, /* [] */0)
          ];
  }
}

function parseConstrainedModExprRegion(p) {
  if (Res_grammar.isModExprStart(p.token)) {
    return parseConstrainedModExpr(p);
  }
  
}

function parsePolyVariantExpr(p) {
  var startPos = p.startPos;
  var match = parseHashIdent(startPos, p);
  var ident = match[0];
  var match$1 = p.token;
  if (match$1 === 18 && p.prevEndPos.pos_lnum === p.startPos.pos_lnum) {
    var lparen = p.startPos;
    var args = parseConstructorArgs(p);
    var rparen = p.prevEndPos;
    var loc_paren = {
      loc_start: lparen,
      loc_end: rparen,
      loc_ghost: false
    };
    var tail;
    var exit = 0;
    if (args) {
      var expr = args.hd;
      var tmp = expr.pexp_desc;
      if (typeof tmp === "number") {
        if (args.tl) {
          exit = 2;
        } else {
          tail = expr;
        }
      } else if (tmp.TAG === /* Pexp_tuple */8) {
        if (args.tl) {
          exit = 2;
        } else {
          tail = p.mode === /* ParseForTypeChecker */0 ? expr : Ast_helper.Exp.tuple(loc_paren, undefined, args);
        }
      } else if (args.tl) {
        exit = 2;
      } else {
        tail = expr;
      }
    } else {
      tail = undefined;
    }
    if (exit === 2) {
      tail = Ast_helper.Exp.tuple(loc_paren, undefined, args);
    }
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: startPos,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    return Ast_helper.Exp.variant(loc, undefined, ident, tail);
  }
  var loc_loc_end$1 = p.prevEndPos;
  var loc$1 = {
    loc_start: startPos,
    loc_end: loc_loc_end$1,
    loc_ghost: false
  };
  return Ast_helper.Exp.variant(loc$1, undefined, ident, undefined);
}

function parseJsx(p) {
  Res_parser.leaveBreadcrumb(p, /* Jsx */4);
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* LessThan */42, p);
  var match = p.token;
  var jsxExpr;
  if (typeof match === "number") {
    jsxExpr = match === /* GreaterThan */41 ? parseJsxFragment(p) : parseJsxName(p);
  } else {
    switch (match.TAG | 0) {
      case /* Lident */4 :
      case /* Uident */5 :
          jsxExpr = parseJsxOpeningOrSelfClosingElement(startPos, p);
          break;
      default:
        jsxExpr = parseJsxName(p);
    }
  }
  Res_parser.eatBreadcrumb(p);
  return {
          pexp_desc: jsxExpr.pexp_desc,
          pexp_loc: jsxExpr.pexp_loc,
          pexp_attributes: {
            hd: jsxAttr,
            tl: /* [] */0
          }
        };
}

function parseListExpr(startPos, p) {
  var listExprs = parseCommaDelimitedReversedList(p, /* ListExpr */53, /* Rbrace */23, parseSpreadExprRegion);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  if (listExprs) {
    var match = listExprs.hd;
    if (match[0]) {
      var exprs = List.rev(List.map((function (prim) {
                  return prim[1];
                }), listExprs.tl));
      return makeListExpression(loc, exprs, match[1]);
    }
    
  }
  var exprs$1 = List.rev(List.map((function (param) {
              if (param[0]) {
                Res_parser.err(undefined, undefined, p, Res_diagnostics.message(listExprSpread));
              }
              return param[1];
            }), listExprs));
  return makeListExpression(loc, exprs$1, undefined);
}

function parseArrayExp(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbracket */20, p);
  var exprs = parseCommaDelimitedRegion(p, /* ExprList */12, /* Rbracket */21, (function (param) {
          return parseNonSpreadExp(arrayExprSpread, param);
        }));
  Res_parser.expect(undefined, /* Rbracket */21, p);
  return Ast_helper.Exp.array({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, undefined, exprs);
}

function parseTupleExpr(first, startPos, p) {
  var exprs_1 = parseCommaDelimitedRegion(p, /* ExprList */12, /* Rparen */19, parseConstrainedExprRegion);
  var exprs = {
    hd: first,
    tl: exprs_1
  };
  Res_parser.expect(undefined, /* Rparen */19, p);
  if (exprs_1) {
    
  } else {
    Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(tupleSingleElement));
  }
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.tuple(loc, undefined, exprs);
}

function parseBracedOrRecordExpr(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var s = p.token;
  var exit = 0;
  if (typeof s === "number") {
    switch (s) {
      case /* DotDotDot */6 :
          Res_parser.next(undefined, p);
          var spreadExpr = parseConstrainedOrCoercedExpr(p);
          Res_parser.expect(undefined, /* Comma */25, p);
          var expr = parseRecordExpr(startPos, Caml_option.some(spreadExpr), /* [] */0, p);
          Res_parser.expect(undefined, /* Rbrace */23, p);
          return expr;
      case /* Rbrace */23 :
          Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(/* Rbrace */23, p.breadcrumbs));
          Res_parser.next(undefined, p);
          var loc_loc_end = p.prevEndPos;
          var loc = {
            loc_start: startPos,
            loc_end: loc_loc_end,
            loc_ghost: false
          };
          var braces = makeBracesAttr(loc);
          return Ast_helper.Exp.construct(loc, {
                      hd: braces,
                      tl: /* [] */0
                    }, $$Location.mkloc({
                          TAG: /* Lident */0,
                          _0: "()"
                        }, loc), undefined);
      default:
        exit = 1;
    }
  } else {
    switch (s.TAG | 0) {
      case /* String */3 :
          var s$1 = s._0;
          var s$2 = p.mode === /* ParseForTypeChecker */0 ? parseStringLiteral(s$1) : s$1;
          var loc_loc_start = p.startPos;
          var loc_loc_end$1 = p.endPos;
          var loc$1 = {
            loc_start: loc_loc_start,
            loc_end: loc_loc_end$1,
            loc_ghost: false
          };
          Res_parser.next(undefined, p);
          var field = $$Location.mkloc({
                TAG: /* Lident */0,
                _0: s$2
              }, loc$1);
          var match = p.token;
          if (match === 24) {
            Res_parser.next(undefined, p);
            var fieldExpr = parseExpr(undefined, p);
            Res_parser.optional(p, /* Comma */25);
            var expr$1 = parseRecordExprWithStringKeys(startPos, [
                  field,
                  fieldExpr
                ], p);
            Res_parser.expect(undefined, /* Rbrace */23, p);
            return expr$1;
          }
          var tag = p.mode === /* ParseForTypeChecker */0 ? "js" : undefined;
          var constant = Ast_helper.Exp.constant(field.loc, undefined, {
                TAG: /* Pconst_string */2,
                _0: s$2,
                _1: tag
              });
          var a = parsePrimaryExpr(constant, undefined, p);
          var e = parseBinaryExpr(undefined, a, p, 1);
          var e$1 = parseTernaryExpr(e, p);
          var match$1 = p.token;
          var exit$1 = 0;
          if (typeof match$1 === "number") {
            if (match$1 !== 8) {
              if (match$1 !== 23) {
                exit$1 = 3;
              } else {
                Res_parser.next(undefined, p);
                var loc_loc_end$2 = p.prevEndPos;
                var loc$2 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$2,
                  loc_ghost: false
                };
                var braces$1 = makeBracesAttr(loc$2);
                return {
                        pexp_desc: e$1.pexp_desc,
                        pexp_loc: e$1.pexp_loc,
                        pexp_attributes: {
                          hd: braces$1,
                          tl: e$1.pexp_attributes
                        }
                      };
              }
            } else {
              var expr$2 = parseExprBlock(e$1, p);
              Res_parser.expect(undefined, /* Rbrace */23, p);
              var loc_loc_end$3 = p.prevEndPos;
              var loc$3 = {
                loc_start: startPos,
                loc_end: loc_loc_end$3,
                loc_ghost: false
              };
              var braces$2 = makeBracesAttr(loc$3);
              return {
                      pexp_desc: expr$2.pexp_desc,
                      pexp_loc: expr$2.pexp_loc,
                      pexp_attributes: {
                        hd: braces$2,
                        tl: expr$2.pexp_attributes
                      }
                    };
            }
          } else {
            exit$1 = 3;
          }
          if (exit$1 === 3) {
            var expr$3 = parseExprBlock(e$1, p);
            Res_parser.expect(undefined, /* Rbrace */23, p);
            var loc_loc_end$4 = p.prevEndPos;
            var loc$4 = {
              loc_start: startPos,
              loc_end: loc_loc_end$4,
              loc_ghost: false
            };
            var braces$3 = makeBracesAttr(loc$4);
            return {
                    pexp_desc: expr$3.pexp_desc,
                    pexp_loc: expr$3.pexp_loc,
                    pexp_attributes: {
                      hd: braces$3,
                      tl: expr$3.pexp_attributes
                    }
                  };
          }
          break;
      case /* Lident */4 :
      case /* Uident */5 :
          exit = 2;
          break;
      default:
        exit = 1;
    }
  }
  switch (exit) {
    case 1 :
        var expr$4 = parseExprBlock(undefined, p);
        Res_parser.expect(undefined, /* Rbrace */23, p);
        var loc_loc_end$5 = p.prevEndPos;
        var loc$5 = {
          loc_start: startPos,
          loc_end: loc_loc_end$5,
          loc_ghost: false
        };
        var braces$4 = makeBracesAttr(loc$5);
        return {
                pexp_desc: expr$4.pexp_desc,
                pexp_loc: expr$4.pexp_loc,
                pexp_attributes: {
                  hd: braces$4,
                  tl: expr$4.pexp_attributes
                }
              };
    case 2 :
        var startToken = p.token;
        var valueOrConstructor = parseValueOrConstructor(p);
        var pathIdent = valueOrConstructor.pexp_desc;
        var exit$2 = 0;
        if (typeof pathIdent === "number" || pathIdent.TAG !== /* Pexp_ident */0) {
          exit$2 = 3;
        } else {
          var pathIdent$1 = pathIdent._0;
          var identEndPos = p.prevEndPos;
          var match$2 = p.token;
          var exit$3 = 0;
          if (typeof match$2 === "number") {
            switch (match$2) {
              case /* Semicolon */8 :
                  var expr$5 = parseExprBlock(Ast_helper.Exp.ident(undefined, undefined, pathIdent$1), p);
                  Res_parser.expect(undefined, /* Rbrace */23, p);
                  var loc_loc_end$6 = p.prevEndPos;
                  var loc$6 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$6,
                    loc_ghost: false
                  };
                  var braces$5 = makeBracesAttr(loc$6);
                  return {
                          pexp_desc: expr$5.pexp_desc,
                          pexp_loc: expr$5.pexp_loc,
                          pexp_attributes: {
                            hd: braces$5,
                            tl: expr$5.pexp_attributes
                          }
                        };
              case /* Rbrace */23 :
                  Res_parser.next(undefined, p);
                  var expr$6 = Ast_helper.Exp.ident(pathIdent$1.loc, undefined, pathIdent$1);
                  var loc_loc_end$7 = p.prevEndPos;
                  var loc$7 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$7,
                    loc_ghost: false
                  };
                  var braces$6 = makeBracesAttr(loc$7);
                  return {
                          pexp_desc: expr$6.pexp_desc,
                          pexp_loc: expr$6.pexp_loc,
                          pexp_attributes: {
                            hd: braces$6,
                            tl: expr$6.pexp_attributes
                          }
                        };
              case /* Colon */24 :
                  Res_parser.next(undefined, p);
                  var fieldExpr$1 = parseExpr(undefined, p);
                  var match$3 = p.token;
                  if (match$3 === 23) {
                    Res_parser.next(undefined, p);
                    var loc_loc_end$8 = p.prevEndPos;
                    var loc$8 = {
                      loc_start: startPos,
                      loc_end: loc_loc_end$8,
                      loc_ghost: false
                    };
                    return Ast_helper.Exp.record(loc$8, undefined, {
                                hd: [
                                  pathIdent$1,
                                  fieldExpr$1
                                ],
                                tl: /* [] */0
                              }, undefined);
                  }
                  Res_parser.expect(undefined, /* Comma */25, p);
                  var expr$7 = parseRecordExpr(startPos, undefined, {
                        hd: [
                          pathIdent$1,
                          fieldExpr$1
                        ],
                        tl: /* [] */0
                      }, p);
                  Res_parser.expect(undefined, /* Rbrace */23, p);
                  return expr$7;
              case /* Comma */25 :
                  Res_parser.next(undefined, p);
                  var valueOrConstructor$1;
                  valueOrConstructor$1 = typeof startToken === "number" || startToken.TAG !== /* Uident */5 ? valueOrConstructor : removeModuleNameFromPunnedFieldValue(valueOrConstructor);
                  var expr$8 = parseRecordExpr(startPos, undefined, {
                        hd: [
                          pathIdent$1,
                          valueOrConstructor$1
                        ],
                        tl: /* [] */0
                      }, p);
                  Res_parser.expect(undefined, /* Rbrace */23, p);
                  return expr$8;
              case /* EqualGreater */57 :
                  var loc$9 = {
                    loc_start: startPos,
                    loc_end: identEndPos,
                    loc_ghost: false
                  };
                  var ident = $$Location.mkloc(Longident.last(pathIdent$1.txt), loc$9);
                  var a$1 = parseEs6ArrowExpression(undefined, {
                        hd: {
                          TAG: /* TermParameter */0,
                          uncurried: false,
                          attrs: /* [] */0,
                          label: /* Nolabel */0,
                          expr: undefined,
                          pat: Ast_helper.Pat.$$var(undefined, undefined, ident),
                          pos: startPos
                        },
                        tl: /* [] */0
                      }, p);
                  var e$2 = parseBinaryExpr(undefined, a$1, p, 1);
                  var e$3 = parseTernaryExpr(e$2, p);
                  var match$4 = p.token;
                  var exit$4 = 0;
                  if (typeof match$4 === "number") {
                    if (match$4 !== 8) {
                      if (match$4 !== 23) {
                        exit$4 = 5;
                      } else {
                        Res_parser.next(undefined, p);
                        var loc_loc_end$9 = p.prevEndPos;
                        var loc$10 = {
                          loc_start: startPos,
                          loc_end: loc_loc_end$9,
                          loc_ghost: false
                        };
                        var braces$7 = makeBracesAttr(loc$10);
                        return {
                                pexp_desc: e$3.pexp_desc,
                                pexp_loc: e$3.pexp_loc,
                                pexp_attributes: {
                                  hd: braces$7,
                                  tl: e$3.pexp_attributes
                                }
                              };
                      }
                    } else {
                      var expr$9 = parseExprBlock(e$3, p);
                      Res_parser.expect(undefined, /* Rbrace */23, p);
                      var loc_loc_end$10 = p.prevEndPos;
                      var loc$11 = {
                        loc_start: startPos,
                        loc_end: loc_loc_end$10,
                        loc_ghost: false
                      };
                      var braces$8 = makeBracesAttr(loc$11);
                      return {
                              pexp_desc: expr$9.pexp_desc,
                              pexp_loc: expr$9.pexp_loc,
                              pexp_attributes: {
                                hd: braces$8,
                                tl: expr$9.pexp_attributes
                              }
                            };
                    }
                  } else {
                    exit$4 = 5;
                  }
                  if (exit$4 === 5) {
                    var expr$10 = parseExprBlock(e$3, p);
                    Res_parser.expect(undefined, /* Rbrace */23, p);
                    var loc_loc_end$11 = p.prevEndPos;
                    var loc$12 = {
                      loc_start: startPos,
                      loc_end: loc_loc_end$11,
                      loc_ghost: false
                    };
                    var braces$9 = makeBracesAttr(loc$12);
                    return {
                            pexp_desc: expr$10.pexp_desc,
                            pexp_loc: expr$10.pexp_loc,
                            pexp_attributes: {
                              hd: braces$9,
                              tl: expr$10.pexp_attributes
                            }
                          };
                  }
                  break;
              default:
                exit$3 = 4;
            }
          } else {
            if (match$2.TAG === /* Lident */4) {
              if (p.prevEndPos.pos_lnum < p.startPos.pos_lnum) {
                Res_parser.expect(undefined, /* Comma */25, p);
                var expr$11 = parseRecordExpr(startPos, undefined, {
                      hd: [
                        pathIdent$1,
                        valueOrConstructor
                      ],
                      tl: /* [] */0
                    }, p);
                Res_parser.expect(undefined, /* Rbrace */23, p);
                return expr$11;
              }
              Res_parser.expect(undefined, /* Colon */24, p);
              var expr$12 = parseRecordExpr(startPos, undefined, {
                    hd: [
                      pathIdent$1,
                      valueOrConstructor
                    ],
                    tl: /* [] */0
                  }, p);
              Res_parser.expect(undefined, /* Rbrace */23, p);
              return expr$12;
            }
            exit$3 = 4;
          }
          if (exit$3 === 4) {
            Res_parser.leaveBreadcrumb(p, /* ExprBlock */10);
            var a$2 = parsePrimaryExpr(Ast_helper.Exp.ident(pathIdent$1.loc, undefined, pathIdent$1), undefined, p);
            var e$4 = parseBinaryExpr(undefined, a$2, p, 1);
            var e$5 = parseTernaryExpr(e$4, p);
            Res_parser.eatBreadcrumb(p);
            var match$5 = p.token;
            var exit$5 = 0;
            if (typeof match$5 === "number") {
              if (match$5 !== 8) {
                if (match$5 !== 23) {
                  exit$5 = 5;
                } else {
                  Res_parser.next(undefined, p);
                  var loc_loc_end$12 = p.prevEndPos;
                  var loc$13 = {
                    loc_start: startPos,
                    loc_end: loc_loc_end$12,
                    loc_ghost: false
                  };
                  var braces$10 = makeBracesAttr(loc$13);
                  return {
                          pexp_desc: e$5.pexp_desc,
                          pexp_loc: e$5.pexp_loc,
                          pexp_attributes: {
                            hd: braces$10,
                            tl: e$5.pexp_attributes
                          }
                        };
                }
              } else {
                var expr$13 = parseExprBlock(e$5, p);
                Res_parser.expect(undefined, /* Rbrace */23, p);
                var loc_loc_end$13 = p.prevEndPos;
                var loc$14 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$13,
                  loc_ghost: false
                };
                var braces$11 = makeBracesAttr(loc$14);
                return {
                        pexp_desc: expr$13.pexp_desc,
                        pexp_loc: expr$13.pexp_loc,
                        pexp_attributes: {
                          hd: braces$11,
                          tl: expr$13.pexp_attributes
                        }
                      };
              }
            } else {
              exit$5 = 5;
            }
            if (exit$5 === 5) {
              var expr$14 = parseExprBlock(e$5, p);
              Res_parser.expect(undefined, /* Rbrace */23, p);
              var loc_loc_end$14 = p.prevEndPos;
              var loc$15 = {
                loc_start: startPos,
                loc_end: loc_loc_end$14,
                loc_ghost: false
              };
              var braces$12 = makeBracesAttr(loc$15);
              return {
                      pexp_desc: expr$14.pexp_desc,
                      pexp_loc: expr$14.pexp_loc,
                      pexp_attributes: {
                        hd: braces$12,
                        tl: expr$14.pexp_attributes
                      }
                    };
            }
            
          }
          
        }
        if (exit$2 === 3) {
          Res_parser.leaveBreadcrumb(p, /* ExprBlock */10);
          var a$3 = parsePrimaryExpr(valueOrConstructor, undefined, p);
          var e$6 = parseBinaryExpr(undefined, a$3, p, 1);
          var e$7 = parseTernaryExpr(e$6, p);
          Res_parser.eatBreadcrumb(p);
          var match$6 = p.token;
          var exit$6 = 0;
          if (typeof match$6 === "number") {
            if (match$6 !== 8) {
              if (match$6 !== 23) {
                exit$6 = 4;
              } else {
                Res_parser.next(undefined, p);
                var loc_loc_end$15 = p.prevEndPos;
                var loc$16 = {
                  loc_start: startPos,
                  loc_end: loc_loc_end$15,
                  loc_ghost: false
                };
                var braces$13 = makeBracesAttr(loc$16);
                return {
                        pexp_desc: e$7.pexp_desc,
                        pexp_loc: e$7.pexp_loc,
                        pexp_attributes: {
                          hd: braces$13,
                          tl: e$7.pexp_attributes
                        }
                      };
              }
            } else {
              var expr$15 = parseExprBlock(e$7, p);
              Res_parser.expect(undefined, /* Rbrace */23, p);
              var loc_loc_end$16 = p.prevEndPos;
              var loc$17 = {
                loc_start: startPos,
                loc_end: loc_loc_end$16,
                loc_ghost: false
              };
              var braces$14 = makeBracesAttr(loc$17);
              return {
                      pexp_desc: expr$15.pexp_desc,
                      pexp_loc: expr$15.pexp_loc,
                      pexp_attributes: {
                        hd: braces$14,
                        tl: expr$15.pexp_attributes
                      }
                    };
            }
          } else {
            exit$6 = 4;
          }
          if (exit$6 === 4) {
            var expr$16 = parseExprBlock(e$7, p);
            Res_parser.expect(undefined, /* Rbrace */23, p);
            var loc_loc_end$17 = p.prevEndPos;
            var loc$18 = {
              loc_start: startPos,
              loc_end: loc_loc_end$17,
              loc_ghost: false
            };
            var braces$15 = makeBracesAttr(loc$18);
            return {
                    pexp_desc: expr$16.pexp_desc,
                    pexp_loc: expr$16.pexp_loc,
                    pexp_attributes: {
                      hd: braces$15,
                      tl: expr$16.pexp_attributes
                    }
                  };
          }
          
        }
        break;
    
  }
}

function parsePatternMatchCase(p) {
  Res_parser.beginRegion(p);
  Res_parser.leaveBreadcrumb(p, /* PatternMatchCase */23);
  var match = p.token;
  if (match === 17) {
    Res_parser.next(undefined, p);
    Res_parser.leaveBreadcrumb(p, /* Pattern */55);
    var lhs = parsePattern(undefined, undefined, p);
    Res_parser.eatBreadcrumb(p);
    var guard = parsePatternGuard(p);
    var match$1 = p.token;
    if (match$1 === 57) {
      Res_parser.next(undefined, p);
    } else {
      recoverEqualGreater(p);
    }
    var rhs = parseExprBlock(undefined, p);
    Res_parser.endRegion(p);
    Res_parser.eatBreadcrumb(p);
    return Ast_helper.Exp.$$case(lhs, guard, rhs);
  }
  Res_parser.endRegion(p);
  Res_parser.eatBreadcrumb(p);
  
}

function parseAliasPattern(attrs, pattern, p) {
  var match = p.token;
  if (match !== 3) {
    return pattern;
  }
  Res_parser.next(undefined, p);
  var match$1 = parseLident(p);
  var name = $$Location.mkloc(match$1[0], match$1[1]);
  var init = pattern.ppat_loc;
  return Ast_helper.Pat.alias({
              loc_start: init.loc_start,
              loc_end: p.prevEndPos,
              loc_ghost: init.loc_ghost
            }, attrs, pattern, name);
}

function parseTuplePattern(attrs, first, startPos, p) {
  var patterns_1 = parseCommaDelimitedRegion(p, /* PatternList */25, /* Rparen */19, parseConstrainedPatternRegion);
  var patterns = {
    hd: first,
    tl: patterns_1
  };
  Res_parser.expect(undefined, /* Rparen */19, p);
  if (patterns_1) {
    
  } else {
    Res_parser.err(startPos, p.prevEndPos, p, Res_diagnostics.message(tupleSingleElement));
  }
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Pat.tuple(loc, attrs, patterns);
}

function parseForRest(hasOpeningParen, pattern, startPos, p) {
  Res_parser.expect(undefined, /* In */53, p);
  var e1 = parseExpr(undefined, p);
  var token = p.token;
  var direction;
  var exit = 0;
  if (typeof token === "number" || token.TAG !== /* Lident */4) {
    exit = 1;
  } else {
    switch (token._0) {
      case "downto" :
          direction = /* Downto */1;
          break;
      case "to" :
          direction = /* Upto */0;
          break;
      default:
        exit = 1;
    }
  }
  if (exit === 1) {
    Res_parser.err(undefined, undefined, p, Res_diagnostics.unexpected(token, p.breadcrumbs));
    direction = /* Upto */0;
  }
  Res_parser.next(undefined, p);
  var e2 = parseExpr(/* WhenExpr */2, p);
  if (hasOpeningParen) {
    Res_parser.expect(undefined, /* Rparen */19, p);
  }
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var bodyExpr = parseExprBlock(undefined, p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.for_(loc, undefined, pattern, e1, e2, direction, bodyExpr);
}

function parseTypeDefinitions(attrs, name, params, startPos, p) {
  var match = parseTypeEquationAndRepresentation(p);
  var cstrs = parseRegion(p, /* TypeConstraint */51, parseTypeConstraint);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var typeDef = Ast_helper.Type.mk(loc, attrs, undefined, undefined, params, cstrs, match[2], match[1], match[0], {
        txt: lidentOfPath(name.txt),
        loc: name.loc
      });
  var _defs = {
    hd: typeDef,
    tl: /* [] */0
  };
  while(true) {
    var defs = _defs;
    var startPos$1 = p.startPos;
    var attrs$1 = parseAttributesAndBinding(p);
    var match$1 = p.token;
    if (match$1 !== 10) {
      return List.rev(defs);
    }
    Res_parser.next(undefined, p);
    var match$2 = p.token;
    var attrs$2;
    if (typeof match$2 === "number" && match$2 >= 84) {
      var exportLoc_loc_start = p.startPos;
      var exportLoc_loc_end = p.endPos;
      var exportLoc = {
        loc_start: exportLoc_loc_start,
        loc_end: exportLoc_loc_end,
        loc_ghost: false
      };
      Res_parser.next(undefined, p);
      var genTypeAttr_0 = $$Location.mkloc("genType", exportLoc);
      var genTypeAttr_1 = {
        TAG: /* PStr */0,
        _0: /* [] */0
      };
      var genTypeAttr = [
        genTypeAttr_0,
        genTypeAttr_1
      ];
      attrs$2 = {
        hd: genTypeAttr,
        tl: attrs$1
      };
    } else {
      attrs$2 = attrs$1;
    }
    var typeDef$1 = parseTypeDef(attrs$2, startPos$1, p);
    _defs = {
      hd: typeDef$1,
      tl: defs
    };
    continue ;
  };
}

function parseTypeExtension(params, attrs, name, p) {
  Res_parser.expect(undefined, /* PlusEqual */39, p);
  var priv = Res_parser.optional(p, /* Private */61) ? /* Private */0 : /* Public */1;
  var constrStart = p.startPos;
  Res_parser.optional(p, /* Bar */17);
  var match = p.token;
  var match$1 = match === 17 ? (Res_parser.next(undefined, p), parseConstrDef(true, p)) : parseConstrDef(true, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: constrStart,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var first = Ast_helper.Te.constructor(loc, match$1[0], undefined, undefined, match$1[1], match$1[2]);
  var loop = function (p, _cs) {
    while(true) {
      var cs = _cs;
      var match = p.token;
      if (match !== 17) {
        return List.rev(cs);
      }
      var startPos = p.startPos;
      Res_parser.next(undefined, p);
      var match$1 = parseConstrDef(true, p);
      var extConstr = Ast_helper.Te.constructor({
            loc_start: startPos,
            loc_end: p.prevEndPos,
            loc_ghost: false
          }, match$1[0], undefined, undefined, match$1[1], match$1[2]);
      _cs = {
        hd: extConstr,
        tl: cs
      };
      continue ;
    };
  };
  var constructors = loop(p, {
        hd: first,
        tl: /* [] */0
      });
  return Ast_helper.Te.mk(attrs, undefined, params, priv, name, constructors);
}

function parseArgument2(p, uncurried) {
  var match = p.token;
  if (typeof match === "number") {
    if (match !== 12) {
      if (match === 48) {
        Res_parser.next(undefined, p);
        var ident = p.token;
        var exit = 0;
        if (typeof ident === "number") {
          exit = 2;
        } else {
          if (ident.TAG === /* Lident */4) {
            var ident$1 = ident._0;
            var startPos = p.startPos;
            Res_parser.next(undefined, p);
            var endPos = p.prevEndPos;
            var loc = {
              loc_start: startPos,
              loc_end: endPos,
              loc_ghost: false
            };
            var propLocAttr_0 = $$Location.mkloc("ns.namedArgLoc", loc);
            var propLocAttr_1 = {
              TAG: /* PStr */0,
              _0: /* [] */0
            };
            var propLocAttr = [
              propLocAttr_0,
              propLocAttr_1
            ];
            var identExpr = Ast_helper.Exp.ident(loc, {
                  hd: propLocAttr,
                  tl: /* [] */0
                }, $$Location.mkloc({
                      TAG: /* Lident */0,
                      _0: ident$1
                    }, loc));
            var match$1 = p.token;
            if (typeof match$1 !== "number") {
              return [
                      uncurried,
                      {
                        TAG: /* Labelled */0,
                        _0: ident$1
                      },
                      identExpr
                    ];
            }
            if (match$1 !== 14) {
              if (match$1 !== 24) {
                if (match$1 !== 49) {
                  return [
                          uncurried,
                          {
                            TAG: /* Labelled */0,
                            _0: ident$1
                          },
                          identExpr
                        ];
                } else {
                  Res_parser.next(undefined, p);
                  return [
                          uncurried,
                          {
                            TAG: /* Optional */1,
                            _0: ident$1
                          },
                          identExpr
                        ];
                }
              }
              Res_parser.next(undefined, p);
              var typ = parseTypExpr(undefined, undefined, undefined, p);
              var loc_loc_end = p.prevEndPos;
              var loc$1 = {
                loc_start: startPos,
                loc_end: loc_loc_end,
                loc_ghost: false
              };
              var expr = Ast_helper.Exp.constraint_(loc$1, {
                    hd: propLocAttr,
                    tl: /* [] */0
                  }, identExpr, typ);
              return [
                      uncurried,
                      {
                        TAG: /* Labelled */0,
                        _0: ident$1
                      },
                      expr
                    ];
            }
            Res_parser.next(undefined, p);
            var match$2 = p.token;
            var label = match$2 === 49 ? (Res_parser.next(undefined, p), {
                  TAG: /* Optional */1,
                  _0: ident$1
                }) : ({
                  TAG: /* Labelled */0,
                  _0: ident$1
                });
            var match$3 = p.token;
            var expr$1;
            var exit$1 = 0;
            if (match$3 === 12 && !isEs6ArrowExpression(false, p)) {
              var loc_loc_start = p.startPos;
              var loc_loc_end$1 = p.endPos;
              var loc$2 = {
                loc_start: loc_loc_start,
                loc_end: loc_loc_end$1,
                loc_ghost: false
              };
              Res_parser.next(undefined, p);
              expr$1 = Ast_helper.Exp.ident(loc$2, undefined, $$Location.mkloc({
                        TAG: /* Lident */0,
                        _0: "_"
                      }, loc$2));
            } else {
              exit$1 = 3;
            }
            if (exit$1 === 3) {
              var expr$2 = parseConstrainedOrCoercedExpr(p);
              expr$1 = {
                pexp_desc: expr$2.pexp_desc,
                pexp_loc: expr$2.pexp_loc,
                pexp_attributes: {
                  hd: propLocAttr,
                  tl: expr$2.pexp_attributes
                }
              };
            }
            return [
                    uncurried,
                    label,
                    expr$1
                  ];
          }
          exit = 2;
        }
        if (exit === 2) {
          Res_parser.err(undefined, undefined, p, Res_diagnostics.lident(ident));
          return [
                  uncurried,
                  /* Nolabel */0,
                  defaultExpr(undefined)
                ];
        }
        
      }
      
    } else if (!isEs6ArrowExpression(false, p)) {
      var loc_loc_start$1 = p.startPos;
      var loc_loc_end$2 = p.endPos;
      var loc$3 = {
        loc_start: loc_loc_start$1,
        loc_end: loc_loc_end$2,
        loc_ghost: false
      };
      Res_parser.next(undefined, p);
      var exp = Ast_helper.Exp.ident(loc$3, undefined, $$Location.mkloc({
                TAG: /* Lident */0,
                _0: "_"
              }, loc$3));
      return [
              uncurried,
              /* Nolabel */0,
              exp
            ];
    }
    
  }
  return [
          uncurried,
          /* Nolabel */0,
          parseConstrainedOrCoercedExpr(p)
        ];
}

function parseLetBindingBody(startPos, attrs, p) {
  Res_parser.beginRegion(p);
  Res_parser.leaveBreadcrumb(p, /* LetBinding */24);
  Res_parser.leaveBreadcrumb(p, /* Pattern */55);
  var pat = parsePattern(undefined, undefined, p);
  Res_parser.eatBreadcrumb(p);
  var match = p.token;
  var match$1;
  if (match === 24) {
    Res_parser.next(undefined, p);
    var match$2 = p.token;
    if (match$2 === 60) {
      Res_parser.next(undefined, p);
      var newtypes = parseLidentList(p);
      Res_parser.expect(undefined, /* Dot */4, p);
      var typ = parseTypExpr(undefined, undefined, undefined, p);
      Res_parser.expect(undefined, /* Equal */14, p);
      var expr = parseExpr(undefined, p);
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: startPos,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      var match$3 = wrapTypeAnnotation(loc, newtypes, typ, expr);
      var pat$1 = Ast_helper.Pat.constraint_(loc, undefined, pat, match$3[1]);
      match$1 = [
        pat$1,
        match$3[0]
      ];
    } else {
      var polyType = parsePolyTypeExpr(p);
      var init = pat.ppat_loc;
      var loc_loc_start = init.loc_start;
      var loc_loc_end$1 = polyType.ptyp_loc.loc_end;
      var loc_loc_ghost = init.loc_ghost;
      var loc$1 = {
        loc_start: loc_loc_start,
        loc_end: loc_loc_end$1,
        loc_ghost: loc_loc_ghost
      };
      var pat$2 = Ast_helper.Pat.constraint_(loc$1, undefined, pat, polyType);
      Res_parser.expect(undefined, /* Equal */14, p);
      var exp = parseExpr(undefined, p);
      var exp$1 = overParseConstrainedOrCoercedOrArrowExpression(p, exp);
      match$1 = [
        pat$2,
        exp$1
      ];
    }
  } else {
    Res_parser.expect(undefined, /* Equal */14, p);
    var exp$2 = overParseConstrainedOrCoercedOrArrowExpression(p, parseExpr(undefined, p));
    match$1 = [
      pat,
      exp$2
    ];
  }
  var loc_loc_end$2 = p.prevEndPos;
  var loc$2 = {
    loc_start: startPos,
    loc_end: loc_loc_end$2,
    loc_ghost: false
  };
  var vb = Ast_helper.Vb.mk(loc$2, attrs, undefined, undefined, match$1[0], match$1[1]);
  Res_parser.eatBreadcrumb(p);
  Res_parser.endRegion(p);
  return vb;
}

function parseArgument(p) {
  if (!(p.token === /* Tilde */48 || p.token === /* Dot */4 || p.token === /* Underscore */12 || Res_grammar.isExprStart(p.token))) {
    return ;
  }
  var match = p.token;
  if (match !== 4) {
    return parseArgument2(p, false);
  }
  Res_parser.next(undefined, p);
  var match$1 = p.token;
  if (match$1 !== 19) {
    return parseArgument2(p, true);
  }
  var unitExpr = Ast_helper.Exp.construct(undefined, undefined, $$Location.mknoloc({
            TAG: /* Lident */0,
            _0: "()"
          }), undefined);
  return [
          true,
          /* Nolabel */0,
          unitExpr
        ];
}

function parsePrimaryModExpr(p) {
  var startPos = p.startPos;
  var modExpr = parseAtomicModuleExpr(p);
  var loop = function (p, _modExpr) {
    while(true) {
      var modExpr = _modExpr;
      var match = p.token;
      if (match !== 18) {
        return modExpr;
      }
      if (p.prevEndPos.pos_lnum !== p.startPos.pos_lnum) {
        return modExpr;
      }
      _modExpr = parseModuleApplication(p, modExpr);
      continue ;
    };
  };
  var modExpr$1 = loop(p, modExpr);
  return {
          pmod_desc: modExpr$1.pmod_desc,
          pmod_loc: {
            loc_start: startPos,
            loc_end: p.prevEndPos,
            loc_ghost: false
          },
          pmod_attributes: modExpr$1.pmod_attributes
        };
}

function parseFunctorModuleExpr(p) {
  var startPos = p.startPos;
  var args = parseFunctorArgs(p);
  var match = p.token;
  var returnType = match === 24 ? (Res_parser.next(undefined, p), parseModuleType(false, undefined, p)) : undefined;
  Res_parser.expect(undefined, /* EqualGreater */57, p);
  var modExpr = parseModuleExpr(p);
  var rhsModuleExpr = returnType !== undefined ? Ast_helper.Mod.constraint_({
          loc_start: modExpr.pmod_loc.loc_start,
          loc_end: returnType.pmty_loc.loc_end,
          loc_ghost: false
        }, undefined, modExpr, returnType) : modExpr;
  var endPos = p.prevEndPos;
  var modExpr$1 = List.fold_right((function (param, acc) {
          return Ast_helper.Mod.functor_({
                      loc_start: param[3],
                      loc_end: endPos,
                      loc_ghost: false
                    }, param[0], param[1], param[2], acc);
        }), args, rhsModuleExpr);
  return {
          pmod_desc: modExpr$1.pmod_desc,
          pmod_loc: {
            loc_start: startPos,
            loc_end: endPos,
            loc_ghost: false
          },
          pmod_attributes: modExpr$1.pmod_attributes
        };
}

function parseUnaryExpr(p) {
  var startPos = p.startPos;
  var token = p.token;
  var exit = 0;
  exit = typeof token === "number" ? (
      token >= 34 ? (
          token >= 38 ? 1 : 2
        ) : (
          token !== 7 ? 1 : 2
        )
    ) : 1;
  switch (exit) {
    case 1 :
        return parsePrimaryExpr(parseAtomicExpr(p), undefined, p);
    case 2 :
        Res_parser.leaveBreadcrumb(p, /* ExprUnary */8);
        var tokenEnd = p.endPos;
        Res_parser.next(undefined, p);
        var operand = parseUnaryExpr(p);
        var unaryExpr = makeUnaryExpr(startPos, tokenEnd, token, operand);
        Res_parser.eatBreadcrumb(p);
        return unaryExpr;
    
  }
}

function parseSwitchExpression(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Switch */55, p);
  var switchExpr = parseExpr(/* WhenExpr */2, p);
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var cases = parsePatternMatching(p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.match_(loc, undefined, switchExpr, cases);
}

function parseTryExpression(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Try */82, p);
  var expr = parseExpr(/* WhenExpr */2, p);
  Res_parser.expect(undefined, Res_token.$$catch, p);
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var cases = parsePatternMatching(p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.try_(loc, undefined, expr, cases);
}

function parseWhileExpression(p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* While */54, p);
  var expr1 = parseExpr(/* WhenExpr */2, p);
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var expr2 = parseExprBlock(undefined, p);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Exp.while_(loc, undefined, expr1, expr2);
}

function parseForExpression(p) {
  var startPos = p.startPos;
  Res_parser.leaveBreadcrumb(p, /* ExprFor */16);
  Res_parser.expect(undefined, /* For */52, p);
  Res_parser.beginRegion(p);
  var match = p.token;
  var forExpr;
  if (match === 18) {
    var lparen = p.startPos;
    Res_parser.next(undefined, p);
    var match$1 = p.token;
    if (match$1 === 19) {
      Res_parser.next(undefined, p);
      var loc_loc_end = p.prevEndPos;
      var loc = {
        loc_start: lparen,
        loc_end: loc_loc_end,
        loc_ghost: false
      };
      var lid = $$Location.mkloc({
            TAG: /* Lident */0,
            _0: "()"
          }, loc);
      var unitPattern = Ast_helper.Pat.construct(undefined, undefined, lid, undefined);
      forExpr = parseForRest(false, parseAliasPattern(/* [] */0, unitPattern, p), startPos, p);
    } else {
      Res_parser.leaveBreadcrumb(p, /* Pattern */55);
      var pat = parsePattern(undefined, undefined, p);
      Res_parser.eatBreadcrumb(p);
      var match$2 = p.token;
      if (match$2 === 25) {
        Res_parser.next(undefined, p);
        var tuplePattern = parseTuplePattern(/* [] */0, pat, lparen, p);
        var pattern = parseAliasPattern(/* [] */0, tuplePattern, p);
        forExpr = parseForRest(false, pattern, startPos, p);
      } else {
        forExpr = parseForRest(true, pat, startPos, p);
      }
    }
  } else {
    Res_parser.leaveBreadcrumb(p, /* Pattern */55);
    var pat$1 = parsePattern(undefined, undefined, p);
    Res_parser.eatBreadcrumb(p);
    forExpr = parseForRest(false, pat$1, startPos, p);
  }
  Res_parser.eatBreadcrumb(p);
  Res_parser.endRegion(p);
  return forExpr;
}

function parseConstructorPatternArgs(p, constr, startPos, attrs) {
  var lparen = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var args = parseCommaDelimitedRegion(p, /* PatternList */25, /* Rparen */19, parseConstrainedPatternRegion);
  Res_parser.expect(undefined, /* Rparen */19, p);
  var args$1;
  var exit = 0;
  if (args) {
    var pat = args.hd;
    var tmp = pat.ppat_desc;
    if (typeof tmp === "number") {
      if (args.tl) {
        exit = 1;
      } else {
        args$1 = pat;
      }
    } else if (tmp.TAG === /* Ppat_tuple */4) {
      if (args.tl) {
        exit = 1;
      } else {
        args$1 = p.mode === /* ParseForTypeChecker */0 ? pat : Ast_helper.Pat.tuple({
                loc_start: lparen,
                loc_end: p.endPos,
                loc_ghost: false
              }, undefined, args);
      }
    } else if (args.tl) {
      exit = 1;
    } else {
      args$1 = pat;
    }
  } else {
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: lparen,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    args$1 = Ast_helper.Pat.construct(loc, undefined, $$Location.mkloc({
              TAG: /* Lident */0,
              _0: "()"
            }, loc), undefined);
  }
  if (exit === 1) {
    args$1 = Ast_helper.Pat.tuple({
          loc_start: lparen,
          loc_end: p.endPos,
          loc_ghost: false
        }, undefined, args);
  }
  return Ast_helper.Pat.construct({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, attrs, constr, args$1);
}

function parseRecordPattern(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var rawFields = parseCommaDelimitedReversedList(p, /* PatternRecord */27, /* Rbrace */23, parseRecordPatternItem);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var match = rawFields && !rawFields.hd[1] ? [
      rawFields.tl,
      /* Open */1
    ] : [
      rawFields,
      /* Closed */0
    ];
  var match$1 = List.fold_left((function (param, curr) {
          var field = curr[1];
          var flag = param[1];
          var fields = param[0];
          if (!field) {
            return [
                    fields,
                    flag
                  ];
          }
          var field$1 = field._0;
          if (curr[0]) {
            Res_parser.err(field$1[1].ppat_loc.loc_start, undefined, p, Res_diagnostics.message(recordPatternSpread));
          }
          return [
                  {
                    hd: field$1,
                    tl: fields
                  },
                  flag
                ];
        }), [
        /* [] */0,
        match[1]
      ], match[0]);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Pat.record(loc, attrs, match$1[0], match$1[1]);
}

function parseModulePattern(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Module */65, p);
  Res_parser.expect(undefined, /* Lparen */18, p);
  var uident = p.token;
  var uident$1;
  if (typeof uident === "number" || uident.TAG !== /* Uident */5) {
    uident$1 = $$Location.mknoloc("_");
  } else {
    var loc_loc_start = p.startPos;
    var loc_loc_end = p.endPos;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    Res_parser.next(undefined, p);
    uident$1 = $$Location.mkloc(uident._0, loc);
  }
  var match = p.token;
  if (match === 24) {
    var colonStart = p.startPos;
    Res_parser.next(undefined, p);
    var packageTypAttrs = parseRegion(p, /* Attribute */50, parseAttribute);
    var packageType = parsePackageType(colonStart, packageTypAttrs, p);
    Res_parser.expect(undefined, /* Rparen */19, p);
    var loc_loc_end$1 = p.prevEndPos;
    var loc$1 = {
      loc_start: startPos,
      loc_end: loc_loc_end$1,
      loc_ghost: false
    };
    var unpack = Ast_helper.Pat.unpack(uident$1.loc, undefined, uident$1);
    return Ast_helper.Pat.constraint_(loc$1, attrs, unpack, packageType);
  }
  Res_parser.expect(undefined, /* Rparen */19, p);
  var loc_loc_end$2 = p.prevEndPos;
  var loc$2 = {
    loc_start: startPos,
    loc_end: loc_loc_end$2,
    loc_ghost: false
  };
  return Ast_helper.Pat.unpack(loc$2, attrs, uident$1);
}

function parseListPattern(startPos, attrs, p) {
  var listPatterns = parseCommaDelimitedReversedList(p, /* PatternOcamlList */26, /* Rbrace */23, parsePatternRegion);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  var filterSpread = function (param) {
    var pattern = param[1];
    if (param[0]) {
      Res_parser.err(pattern.ppat_loc.loc_start, undefined, p, Res_diagnostics.message(listPatternSpread));
      return pattern;
    } else {
      return pattern;
    }
  };
  if (listPatterns) {
    var match = listPatterns.hd;
    if (match[0]) {
      var patterns = List.rev(List.map(filterSpread, listPatterns.tl));
      var pat = makeListPattern(loc, patterns, match[1]);
      return {
              ppat_desc: pat.ppat_desc,
              ppat_loc: loc,
              ppat_attributes: attrs
            };
    }
    
  }
  var patterns$1 = List.rev(List.map(filterSpread, listPatterns));
  var pat$1 = makeListPattern(loc, patterns$1, undefined);
  return {
          ppat_desc: pat$1.ppat_desc,
          ppat_loc: loc,
          ppat_attributes: attrs
        };
}

function parseVariantPatternArgs(p, ident, startPos, attrs) {
  var lparen = p.startPos;
  Res_parser.expect(undefined, /* Lparen */18, p);
  var patterns = parseCommaDelimitedRegion(p, /* PatternList */25, /* Rparen */19, parseConstrainedPatternRegion);
  var args;
  var exit = 0;
  if (patterns) {
    var pat = patterns.hd;
    var tmp = pat.ppat_desc;
    if (typeof tmp === "number") {
      if (patterns.tl) {
        exit = 1;
      } else {
        args = pat;
      }
    } else if (tmp.TAG === /* Ppat_tuple */4) {
      if (patterns.tl) {
        exit = 1;
      } else {
        args = p.mode === /* ParseForTypeChecker */0 ? pat : Ast_helper.Pat.tuple({
                loc_start: lparen,
                loc_end: p.endPos,
                loc_ghost: false
              }, undefined, patterns);
      }
    } else if (patterns.tl) {
      exit = 1;
    } else {
      args = pat;
    }
  } else {
    var loc_loc_end = p.prevEndPos;
    var loc = {
      loc_start: lparen,
      loc_end: loc_loc_end,
      loc_ghost: false
    };
    args = Ast_helper.Pat.construct(loc, undefined, $$Location.mkloc({
              TAG: /* Lident */0,
              _0: "()"
            }, loc), undefined);
  }
  if (exit === 1) {
    args = Ast_helper.Pat.tuple({
          loc_start: lparen,
          loc_end: p.endPos,
          loc_ghost: false
        }, undefined, patterns);
  }
  Res_parser.expect(undefined, /* Rparen */19, p);
  return Ast_helper.Pat.variant({
              loc_start: startPos,
              loc_end: p.prevEndPos,
              loc_ghost: false
            }, attrs, ident, args);
}

function parseOrPattern(pattern1, p) {
  var _pattern1 = pattern1;
  while(true) {
    var pattern1$1 = _pattern1;
    var match = p.token;
    if (match !== 17) {
      return pattern1$1;
    }
    Res_parser.next(undefined, p);
    var pattern2 = parsePattern(undefined, false, p);
    var init = pattern1$1.ppat_loc;
    var loc_loc_start = init.loc_start;
    var loc_loc_end = pattern2.ppat_loc.loc_end;
    var loc_loc_ghost = init.loc_ghost;
    var loc = {
      loc_start: loc_loc_start,
      loc_end: loc_loc_end,
      loc_ghost: loc_loc_ghost
    };
    _pattern1 = Ast_helper.Pat.or_(loc, undefined, pattern1$1, pattern2);
    continue ;
  };
}

function parseArrayPattern(attrs, p) {
  var startPos = p.startPos;
  Res_parser.expect(undefined, /* Lbracket */20, p);
  var patterns = parseCommaDelimitedRegion(p, /* PatternList */25, /* Rbracket */21, (function (param) {
          return parseNonSpreadPattern(arrayPatternSpread, param);
        }));
  Res_parser.expect(undefined, /* Rbracket */21, p);
  var loc_loc_end = p.prevEndPos;
  var loc = {
    loc_start: startPos,
    loc_end: loc_loc_end,
    loc_ghost: false
  };
  return Ast_helper.Pat.array(loc, attrs, patterns);
}

function parseJsFfiDeclarations(p) {
  Res_parser.expect(undefined, /* Lbrace */22, p);
  var decls = parseCommaDelimitedRegion(p, /* JsFfiImport */54, /* Rbrace */23, parseJsFfiDeclaration);
  Res_parser.expect(undefined, /* Rbrace */23, p);
  return decls;
}

function parseJsFfiScope(p) {
  var match = p.token;
  if (typeof match === "number") {
    return /* Global */0;
  }
  if (match.TAG !== /* Lident */4) {
    return /* Global */0;
  }
  if (match._0 !== "from") {
    return /* Global */0;
  }
  Res_parser.next(undefined, p);
  var s = p.token;
  if (typeof s === "number") {
    return /* Global */0;
  }
  switch (s.TAG | 0) {
    case /* String */3 :
        Res_parser.next(undefined, p);
        return {
                TAG: /* Module */0,
                _0: s._0
              };
    case /* Lident */4 :
    case /* Uident */5 :
        break;
    default:
      return /* Global */0;
  }
  var value = parseIdentPath(p);
  return {
          TAG: /* Scope */1,
          _0: value
        };
}

function parseJsxProps(p) {
  return parseRegion(p, /* JsxAttribute */5, parseJsxProp);
}

function parseTypeConstraints(p) {
  return parseRegion(p, /* TypeConstraint */51, parseTypeConstraint);
}

function parseAttributes(p) {
  return parseRegion(p, /* Attribute */50, parseAttribute);
}

function parseSpecification(p) {
  return parseRegion(p, /* Specification */47, parseSignatureItemRegion);
}

function parseImplementation(p) {
  return parseRegion(p, /* Implementation */49, parseStructureItemRegion);
}

var Doc;

var Grammar;

var Token;

var Diagnostics;

var CommentTable;

var ResPrinter;

var Scanner;

var JsFfi;

var Parser;

export {
  Doc ,
  Grammar ,
  Token ,
  Diagnostics ,
  CommentTable ,
  ResPrinter ,
  Scanner ,
  JsFfi ,
  Parser ,
  mkLoc ,
  Recover ,
  ErrorMessages ,
  jsxAttr ,
  uncurryAttr ,
  ternaryAttr ,
  ifLetAttr ,
  suppressFragileMatchWarningAttr ,
  makeBracesAttr ,
  templateLiteralAttr ,
  getClosingToken ,
  goToClosing ,
  isEs6ArrowExpression ,
  isEs6ArrowFunctor ,
  isEs6ArrowType ,
  buildLongident ,
  makeInfixOperator ,
  negateString ,
  makeUnaryExpr ,
  makeListExpression ,
  makeListPattern ,
  lidentOfPath ,
  makeNewtypes ,
  wrapTypeAnnotation ,
  processUnderscoreApplication ,
  hexValue ,
  removeModuleNameFromPunnedFieldValue ,
  parseStringLiteral ,
  parseLident ,
  parseIdent ,
  parseHashIdent ,
  parseValuePath ,
  parseValuePathAfterDot ,
  parseValuePathTail ,
  parseModuleLongIdentTail ,
  parseModuleLongIdent ,
  parseIdentPath ,
  verifyJsxOpeningClosingName ,
  string_of_pexp_ident ,
  parseOpenDescription ,
  parseTemplateStringLiteral ,
  parseConstant ,
  parseTemplateConstant ,
  parseCommaDelimitedRegion ,
  parseCommaDelimitedReversedList ,
  parseDelimitedRegion ,
  parseRegion ,
  parsePattern ,
  skipTokensAndMaybeRetry ,
  parseAliasPattern ,
  parseOrPattern ,
  parseNonSpreadPattern ,
  parseConstrainedPattern ,
  parseConstrainedPatternRegion ,
  parseRecordPatternField ,
  parseRecordPatternItem ,
  parseRecordPattern ,
  parseTuplePattern ,
  parsePatternRegion ,
  parseModulePattern ,
  parseListPattern ,
  parseArrayPattern ,
  parseConstructorPatternArgs ,
  parseVariantPatternArgs ,
  parseExpr ,
  parseTernaryExpr ,
  parseEs6ArrowExpression ,
  parseParameter ,
  parseParameterList ,
  parseParameters ,
  parseCoercedExpr ,
  parseConstrainedOrCoercedExpr ,
  parseConstrainedExprRegion ,
  parseAtomicExpr ,
  parseFirstClassModuleExpr ,
  parseBracketAccess ,
  parsePrimaryExpr ,
  parseUnaryExpr ,
  parseOperandExpr ,
  parseBinaryExpr ,
  parseTemplateExpr ,
  overParseConstrainedOrCoercedOrArrowExpression ,
  parseLetBindingBody ,
  parseAttributesAndBinding ,
  parseLetBindings ,
  parseJsxName ,
  parseJsxOpeningOrSelfClosingElement ,
  parseJsx ,
  parseJsxFragment ,
  parseJsxProp ,
  parseJsxProps ,
  parseJsxChildren ,
  parseBracedOrRecordExpr ,
  parseRecordRowWithStringKey ,
  parseRecordRow ,
  parseRecordExprWithStringKeys ,
  parseRecordExpr ,
  parseNewlineOrSemicolonExprBlock ,
  parseExprBlockItem ,
  parseExprBlock ,
  parseTryExpression ,
  parseIfCondition ,
  parseThenBranch ,
  parseElseBranch ,
  parseIfExpr ,
  parseIfLetExpr ,
  parseIfOrIfLetExpression ,
  parseForRest ,
  parseForExpression ,
  parseWhileExpression ,
  parsePatternGuard ,
  parsePatternMatchCase ,
  parsePatternMatching ,
  parseSwitchExpression ,
  parseArgument ,
  parseArgument2 ,
  parseCallExpr ,
  parseValueOrConstructor ,
  parsePolyVariantExpr ,
  parseConstructorArgs ,
  parseTupleExpr ,
  parseSpreadExprRegion ,
  parseListExpr ,
  parseNonSpreadExp ,
  parseArrayExp ,
  parsePolyTypeExpr ,
  parseTypeVarList ,
  parseLidentList ,
  parseAtomicTypExpr ,
  parsePackageType ,
  parsePackageConstraints ,
  parsePackageConstraint ,
  parseRecordOrObjectType ,
  parseTypeAlias ,
  parseTypeParameter ,
  parseTypeParameters ,
  parseEs6ArrowType ,
  parseTypExpr ,
  parseArrowTypeRest ,
  parseTypExprRegion ,
  parseTupleType ,
  parseTypeConstructorArgRegion ,
  parseTypeConstructorArgs ,
  parseStringFieldDeclaration ,
  parseFieldDeclaration ,
  parseFieldDeclarationRegion ,
  parseRecordDeclaration ,
  parseConstrDeclArgs ,
  parseTypeConstructorDeclarationWithBar ,
  parseTypeConstructorDeclaration ,
  parseTypeConstructorDeclarations ,
  parseTypeRepresentation ,
  parseTypeParam ,
  parseTypeParams ,
  parseTypeConstraint ,
  parseTypeConstraints ,
  parseTypeEquationOrConstrDecl ,
  parseRecordOrObjectDecl ,
  parsePrivateEqOrRepr ,
  parsePolymorphicVariantType ,
  parseTagName ,
  parseTagNames ,
  parseTagSpecFulls ,
  parseTagSpecFull ,
  parseTagSpecs ,
  parseTagSpec ,
  parseTagSpecFirst ,
  parsePolymorphicVariantTypeSpecHash ,
  parsePolymorphicVariantTypeArgs ,
  parseTypeEquationAndRepresentation ,
  parseTypeDef ,
  parseTypeExtension ,
  parseTypeDefinitions ,
  parseTypeDefinitionOrExtension ,
  parseExternalDef ,
  parseConstrDef ,
  parseExceptionDef ,
  parseNewlineOrSemicolonStructure ,
  parseStructureItemRegion ,
  parseJsImport ,
  parseJsExport ,
  parseSignJsExport ,
  parseJsFfiScope ,
  parseJsFfiDeclarations ,
  parseJsFfiDeclaration ,
  parseIncludeStatement ,
  parseAtomicModuleExpr ,
  parsePrimaryModExpr ,
  parseFunctorArg ,
  parseFunctorArgs ,
  parseFunctorModuleExpr ,
  parseModuleExpr ,
  parseConstrainedModExpr ,
  parseConstrainedModExprRegion ,
  parseModuleApplication ,
  parseModuleOrModuleTypeImplOrPackExpr ,
  parseModuleTypeImpl ,
  parseMaybeRecModuleBinding ,
  parseModuleBinding ,
  parseModuleBindingBody ,
  parseModuleBindings ,
  parseAtomicModuleType ,
  parseFunctorModuleType ,
  parseModuleType ,
  parseWithConstraints ,
  parseWithConstraint ,
  parseModuleTypeOf ,
  parseNewlineOrSemicolonSignature ,
  parseSignatureItemRegion ,
  parseRecModuleSpec ,
  parseRecModuleDeclaration ,
  parseModuleDeclarationOrAlias ,
  parseModuleTypeDeclaration ,
  parseSignLetDesc ,
  parseAttributeId ,
  parsePayload ,
  parseAttribute ,
  parseAttributes ,
  parseStandaloneAttribute ,
  parseExtension ,
  parseSpecification ,
  parseImplementation ,
  
}
/* id Not a pure module */
