function words(e) {
  for (var c = {}, l = e.split(" "), u = 0; u < l.length; ++u) c[l[u]] = true;
  return c;
}
var keywords = words("abstract as assert boolean break byte case catch char class const continue def default do double else enum extends final finally float for goto if implements import in instanceof int interface long native new package private protected public return short static strictfp super switch synchronized threadsafe throw throws trait transient try void volatile while"), blockKeywords = words("catch class def do else enum finally for if interface switch trait try while"), standaloneKeywords = words("return break continue"), atoms = words("null true false this"), curPunc;
function tokenBase(e, p) {
  var m = e.next();
  if (m == '"' || m == "'") return startString(m, e, p);
  if (/[\[\]{}\(\),;\:\.]/.test(m)) return curPunc = m, null;
  if (/\d/.test(m)) return e.eatWhile(/[\w\.]/), e.eat(/eE/) && (e.eat(/\+\-/), e.eatWhile(/\d/)), "number";
  if (m == "/") {
    if (e.eat("*")) return p.tokenize.push(tokenComment), tokenComment(e, p);
    if (e.eat("/")) return e.skipToEnd(), "comment";
    if (expectExpression(p.lastToken, false)) return startString(m, e, p);
  }
  if (m == "-" && e.eat(">")) return curPunc = "->", null;
  if (/[+\-*&%=<>!?|\/~]/.test(m)) return e.eatWhile(/[+\-*&%=<>|~]/), "operator";
  if (e.eatWhile(/[\w\$_]/), m == "@") return e.eatWhile(/[\w\$_\.]/), "meta";
  if (p.lastToken == ".") return "property";
  if (e.eat(":")) return curPunc = "proplabel", "property";
  var h = e.current();
  return atoms.propertyIsEnumerable(h) ? "atom" : keywords.propertyIsEnumerable(h) ? (blockKeywords.propertyIsEnumerable(h) ? curPunc = "newstatement" : standaloneKeywords.propertyIsEnumerable(h) && (curPunc = "standalone"), "keyword") : "variable";
}
tokenBase.isBase = true;
function startString(e, c, l) {
  var u = false;
  if (e != "/" && c.eat(e)) if (c.eat(e)) u = true;
  else return "string";
  function d(c2, l2) {
    for (var d2 = false, f, p = !u; (f = c2.next()) != null; ) {
      if (f == e && !d2) {
        if (!u) break;
        if (c2.match(e + e)) {
          p = true;
          break;
        }
      }
      if (e == '"' && f == "$" && !d2) {
        if (c2.eat("{")) return l2.tokenize.push(tokenBaseUntilBrace()), "string";
        if (c2.match(/^\w/, false)) return l2.tokenize.push(tokenVariableDeref), "string";
      }
      d2 = !d2 && f == "\\";
    }
    return p && l2.tokenize.pop(), "string";
  }
  return l.tokenize.push(d), d(c, l);
}
function tokenBaseUntilBrace() {
  var e = 1;
  function c(c2, l) {
    if (c2.peek() == "}") {
      if (e--, e == 0) return l.tokenize.pop(), l.tokenize[l.tokenize.length - 1](c2, l);
    } else c2.peek() == "{" && e++;
    return tokenBase(c2, l);
  }
  return c.isBase = true, c;
}
function tokenVariableDeref(e, c) {
  var l = e.match(/^(\.|[\w\$_]+)/);
  return (!l || !e.match(l[0] == "." ? /^[\w$_]/ : /^\./)) && c.tokenize.pop(), l ? l[0] == "." ? null : "variable" : c.tokenize[c.tokenize.length - 1](e, c);
}
function tokenComment(e, c) {
  for (var l = false, u; u = e.next(); ) {
    if (u == "/" && l) {
      c.tokenize.pop();
      break;
    }
    l = u == "*";
  }
  return "comment";
}
function expectExpression(e, c) {
  return !e || e == "operator" || e == "->" || /[\.\[\{\(,;:]/.test(e) || e == "newstatement" || e == "keyword" || e == "proplabel" || e == "standalone" && !c;
}
function Context(e, c, l, u, d) {
  this.indented = e, this.column = c, this.type = l, this.align = u, this.prev = d;
}
function pushContext(e, c, l) {
  return e.context = new Context(e.indented, c, l, null, e.context);
}
function popContext(e) {
  var c = e.context.type;
  return (c == ")" || c == "]" || c == "}") && (e.indented = e.context.indented), e.context = e.context.prev;
}
const groovy = {
  name: "groovy",
  startState: function(e) {
    return {
      tokenize: [tokenBase],
      context: new Context(-e, 0, "top", false),
      indented: 0,
      startOfLine: true,
      lastToken: null
    };
  },
  token: function(e, c) {
    var l = c.context;
    if (e.sol() && (l.align ?? (l.align = false), c.indented = e.indentation(), c.startOfLine = true, l.type == "statement" && !expectExpression(c.lastToken, true) && (popContext(c), l = c.context)), e.eatSpace()) return null;
    curPunc = null;
    var u = c.tokenize[c.tokenize.length - 1](e, c);
    if (u == "comment") return u;
    if (l.align ?? (l.align = true), (curPunc == ";" || curPunc == ":") && l.type == "statement") popContext(c);
    else if (curPunc == "->" && l.type == "statement" && l.prev.type == "}") popContext(c), c.context.align = false;
    else if (curPunc == "{") pushContext(c, e.column(), "}");
    else if (curPunc == "[") pushContext(c, e.column(), "]");
    else if (curPunc == "(") pushContext(c, e.column(), ")");
    else if (curPunc == "}") {
      for (; l.type == "statement"; ) l = popContext(c);
      for (l.type == "}" && (l = popContext(c)); l.type == "statement"; ) l = popContext(c);
    } else curPunc == l.type ? popContext(c) : (l.type == "}" || l.type == "top" || l.type == "statement" && curPunc == "newstatement") && pushContext(c, e.column(), "statement");
    return c.startOfLine = false, c.lastToken = curPunc || u, u;
  },
  indent: function(e, c, l) {
    if (!e.tokenize[e.tokenize.length - 1].isBase) return null;
    var u = c && c.charAt(0), d = e.context;
    d.type == "statement" && !expectExpression(e.lastToken, true) && (d = d.prev);
    var f = u == d.type;
    return d.type == "statement" ? d.indented + (u == "{" ? 0 : l.unit) : d.align ? d.column + (f ? 0 : 1) : d.indented + (f ? 0 : l.unit);
  },
  languageData: {
    indentOnInput: /^\s*[{}]$/,
    commentTokens: {
      line: "//",
      block: {
        open: "/*",
        close: "*/"
      }
    },
    closeBrackets: { brackets: [
      "(",
      "[",
      "{",
      "'",
      '"',
      "'''",
      '"""'
    ] }
  }
};
export {
  groovy as t
};
