output: #fixed code
                                  protected ASTNode nextToken() {
          /**
           * If the cursor is at the end of the expression, we have nothing more to do:
           * return null.
           */
          if (cursor >= length) {
              return null;
          }
          else if (!splitAccumulator.isEmpty()) {
              return lastNode = (ASTNode) splitAccumulator.pop();
          }
  
          int brace, start = cursor;
  
          /**
           * Because of parser recursion for sub-expression parsing, we sometimes need to remain
           * certain field states.  We do not reset for assignments, boolean mode, list creation or
           * a capture only mode.
           */
          fields = fields & (ASTNode.INLINE_COLLECTION | ASTNode.COMPILE_IMMEDIATE);
  
          boolean capture = false;
          boolean union = false;
  
          if (debugSymbols) {
              if (!lastWasLineLabel) {
                  if (getParserContext().getSourceFile() == null) {
                      throw new CompileException("unable to produce debugging symbols: source name must be provided.");
                  }
  
                  ParserContext pCtx = getParserContext();
  
                  line = pCtx.getLineCount();
  
                  int scan = cursor;
  
                  while (expr[scan] == '\n') {
                      scan++;
                      line++;
                  }
  
                  if (lastWasComment) {
                      line++;
                      lastWasComment = false;
                  }
  
                  pCtx.setLineCount(line);
  
                  if (!pCtx.isKnownLine(pCtx.getSourceFile(), line)) {
  
                      lastWasLineLabel = true;
  
                      pCtx.setLineAndOffset(line, cursor);
                      pCtx.addKnownLine(pCtx.getSourceFile(), line);
  
                      LineLabel ll = new LineLabel(pCtx.getSourceFile(), line);
                      if (pCtx.getFirstLineLabel() == null) pCtx.setFirstLineLabel(ll);
  
                      return lastNode = ll;
                  }
              }
              else {
                  lastWasComment = lastWasLineLabel = false;
              }
          }
  
          /**
           * Skip any whitespace currently under the starting point.
           */
          while (start < length && isWhitespace(expr[start])) start++;
  
          /**
           * From here to the end of the method is the core MVEL parsing code.  Fiddling around here is asking for
           * trouble unless you really know what you're doing.
           */
          for (cursor = start; cursor < length;) {
              if (isIdentifierPart(expr[cursor])) {
                  /**
                   * If the current character under the cursor is a valid
                   * part of an identifier, we keep capturing.
                   */
                  capture = true;
                  cursor++;
              }
              else if (capture) {
                  String t;
                  if (OPERATORS.containsKey(t = new String(expr, start, cursor - start))) {
                      switch (OPERATORS.get(t)) {
                          case NEW:
                              start = cursor + 1;
                              captureToEOT();
                              return new NewObjectNode(subArray(start, cursor), fields);
  
                          case ASSERT:
                              start = cursor + 1;
                              captureToEOS();
                              return new AssertNode(subArray(start, cursor--), fields);
  
                          case RETURN:
                              start = cursor + 1;
                              captureToEOS();
                              return new ReturnNode(subArray(start, cursor), fields);
  
                          case IF:
                              fields |= ASTNode.BLOCK_IF;
                              return captureCodeBlock();
  
                          case FOREACH:
                              fields |= ASTNode.BLOCK_FOREACH;
                              return captureCodeBlock();
  
                          case WITH:
                              fields |= ASTNode.BLOCK_WITH;
                              return captureCodeBlock();
  
                          case IMPORT:
                              start = cursor + 1;
                              captureToEOS();
                              ImportNode importNode = new ImportNode(subArray(start, cursor--), fields);
                              getParserContext().addImport(getSimpleClassName(importNode.getImportClass()), importNode.getImportClass());
                              return importNode;
  
                          case IMPORT_STATIC:
                              start = cursor + 1;
                              captureToEOS();
                              return new StaticImportNode(subArray(start, cursor--), fields);
                      }
                  }
  
                  /**
                   * If we *were* capturing a token, and we just hit a non-identifier
                   * character, we stop and figure out what to do.
                   */
                  skipWhitespace();
  
                  if (expr[cursor] == '(') {
                      fields |= ASTNode.METHOD;
  
                      /**
                       * If the current token is a method call or a constructor, we
                       * simply capture the entire parenthesized range and allow
                       * reduction to be dealt with through sub-parsing the property.
                       */
                      cursor++;
                      for (brace = 1; cursor < length && brace > 0;) {
                          switch (expr[cursor++]) {
                              case'(':
                                  brace++;
                                  break;
                              case')':
                                  brace--;
                                  break;
                              case'\'':
                                  cursor = captureStringLiteral('\'', expr, cursor, length) + 1;
                                  break;
  
                              case'"':
                                  cursor = captureStringLiteral('"', expr, cursor, length) + 1;
                                  break;
  
                          }
                      }
  
                      /**
                       * If the brace counter is greater than 0, we know we have
                       * unbalanced braces in the expression.  So we throw a
                       * optimize error now.
                       */
                      if (brace > 0)
                          throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, cursor);
                  }
  
                  /**
                   * If we encounter any of the following cases, we are still dealing with
                   * a contiguous token.
                   */
                  String name;
                  if (cursor < length) {
                      switch (expr[cursor]) {
                          case'+':
                              switch (lookAhead(1)) {
                                  case'+':
                                      ASTNode n = new PostFixIncNode(subArray(start, cursor), fields);
                                      cursor += 2;
                                      return n;
  
                                  case'=':
                                      name = new String(expr, start, trimLeft(cursor));
                                      start = cursor += 2;
                                      captureToEOS();
  
                                      if (union) {
                                          return new DeepAssignmentNode(subArray(start, cursor), fields, Operator.ADD, t);
                                      }
                                      else {
                                          return new AssignmentNode(subArray(start, cursor), fields, Operator.ADD, name);
                                      }
                              }
  
                              break;
  
                          case'-':
                              switch (lookAhead(1)) {
                                  case'-':
                                      ASTNode n = new PostFixDecNode(subArray(start, cursor), fields);
                                      cursor += 2;
                                      return n;
  
                                  case'=':
                                      name = new String(expr, start, trimLeft(cursor));
                                      start = cursor += 2;
                                      captureToEOS();
                                      return new AssignSub(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case'*':
                              if (isAt('=', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignMult(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case'/':
                              if (isAt('=', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignDiv(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case']':
                          case'[':
                              balancedCapture('[');
                              cursor++;
                              continue;
                          case'.':
                              union = true;
                              cursor++;
                              continue;
  
                          case'~':
                              if (isAt('=', 1)) {
                                  char[] stmt = subArray(start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOT();
                                  return new RegExMatch(stmt, fields, subArray(start, cursor));
                              }
                              break;
  
                          case'=':
                              if (isAt('+', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignAdd(subArray(start, cursor), fields, name);
                              }
  
                              if (greedy && !isAt('=', 1)) {
                                  cursor++;
  
                                  fields |= ASTNode.ASSIGN;
  
                                  skipWhitespace();
                                  captureToEOS();
  
                                  if (union) {
                                      return new DeepAssignmentNode(subArray(start, cursor), fields);
                                  }
                                  else if (lastWasIdentifier) {
  
                                      /**
                                       * Check for typing information.
                                       */
                                      if (lastNode.getLiteralValue() instanceof String) {
                                          if (getParserContext().hasImport((String) lastNode.getLiteralValue())) {
                                              lastNode.setLiteralValue(getParserContext().getImport((String) lastNode.getLiteralValue()));
                                              lastNode.setAsLiteral();
                                          }
                                          else {
                                              try {
                                                  /**
                                                   *  take a stab in the dark and try and load the class
                                                   */
                                                  lastNode.setLiteralValue(createClass((String) lastNode.getLiteralValue()));
                                                  lastNode.setAsLiteral();
                                              }
                                              catch (ClassNotFoundException e) {
                                                  /**
                                                   * Just fail through.
                                                   */
                                              }
                                          }
                                      }
  
                                      if (lastNode.isLiteral() && lastNode.getLiteralValue() instanceof Class) {
                                          lastNode.setDiscard(true);
  
                                          captureToEOS();
                                          return new TypedVarNode(subArray(start, cursor), fields, (Class)
                                                  lastNode.getLiteralValue());
                                      }
  
                                      throw new ParseException("unknown class: " + lastNode.getLiteralValue());
                                  }
                                  else {
                                      return new AssignmentNode(subArray(start, cursor), fields);
                                  }
                              }
                      }
                  }
  
                  /**
                   * Produce the token.
                   */
                  trimWhitespace();
  
                  if (parserContext != null) {
                      char[] _subset = subset(expr, start, cursor - start);
                      int offset;
  
                      Class cls;
                      if ((offset = ArrayTools.findFirst('.', _subset)) != -1) {
                          String iStr;
                          if (getParserContext().hasImport(iStr = new String(_subset, 0, offset))) {
                              lastWasIdentifier = true;
                              return lastNode = new LiteralDeepPropertyNode(subset(_subset, offset + 1, _subset.length - offset - 1), fields, getParserContext().getImport(iStr)); 
  // /                            return lastNode = new Union(_subset, offset + 1, _subset.length, fields, new LiteralNode(getParserContext().getImport(iStr)));
                          }
  //                        else if ((cls = createClassSafe(iStr = new String(_subset, offset = ArrayTools.findLast('.', _subset), _subset.length - offset))) != null) {
  //
  //                        }
  
                      }
  
                      else {
                          ASTNode node = new ASTNode(_subset, 0, _subset.length, fields);
                          lastWasIdentifier = node.isIdentifier();
                          return lastNode = node;
                      }
                  }
  
                  return createToken(expr, start, cursor, fields);
              }
              else
                  switch (expr[cursor]) {
                      case'@': {
                          start++;
                          captureToEOT();
  
                          String interceptorName = new String(expr, start, cursor - start);
  
                          if (getParserContext().getInterceptors() == null || !getParserContext().getInterceptors().
                                  containsKey(interceptorName)) {
                              throw new CompileException("reference to undefined interceptor: " + interceptorName, expr, cursor);
                          }
  
                          return new InterceptorWrapper(getParserContext().getInterceptors().get(interceptorName), nextToken());
                      }
  
                      case'=':
                          return createToken(expr, start, (cursor += 2), fields);
  
                      case'-':
                          if (isAt('-', 1)) {
                              start = cursor += 2;
                              captureToEOT();
                              return new PreFixDecNode(subArray(start, cursor), fields);
                          }
                          else if ((cursor > 0 && !isWhitespace(lookBehind(1))) || !isDigit(lookAhead(1))) {
                              return createToken(expr, start, cursor++ + 1, fields);
                          }
                          else if ((cursor - 1) < 0 || (!isDigit(lookBehind(1))) && isDigit(lookAhead(1))) {
                              cursor++;
                              break;
                          }
  
                      case'+':
                          if (isAt('+', 1)) {
                              start = cursor += 2;
                              captureToEOT();
                              return new PreFixIncNode(subArray(start, cursor), fields);
                          }
                          return createToken(expr, start, cursor++ + 1, fields);
  
                      case'*':
                          if (isAt('*', 1)) {
                              cursor++;
                          }
                          return createToken(expr, start, cursor++ + 1, fields);
  
                      case';':
                          cursor++;
                          lastWasIdentifier = false;
                          return lastNode = new EndOfStatement();
  
                      case'#':
                      case'/':
                          if (isAt(expr[cursor], 1)) {
                              /**
                               * Handle single line comments.
                               */
                              while (cursor < length && expr[cursor] != '\n') cursor++;
  
                              if (debugSymbols) {
                                  line = getParserContext().getLineCount();
  
                                  skipWhitespaceWithLineAccounting();
  
                                  if (lastNode instanceof LineLabel) {
                                      getParserContext().getFirstLineLabel().setLineNumber(line);
                                  }
  
                                  lastWasComment = true;
  
                                  getParserContext().setLineCount(line);
                              }
                              else if (cursor < length) {
                                  skipWhitespace();
                              }
  
                              if ((start = cursor) >= length) return null;
  
                              continue;
                          }
                          else if (expr[cursor] == '/' && isAt('*', 1)) {
                              /**
                               * Handle multi-line comments.
                               */
                              int len = length - 1;
  
                              /**
                               * This probably seems highly redundant, but sub-compilations within the same
                               * source will spawn a new compiler, and we need to sync this with the
                               * parser context;
                               */
                              if (debugSymbols) {
                                  line = getParserContext().getLineCount();
                              }
  
                              while (true) {
                                  cursor++;
                                  /**
                                   * Since multi-line comments may cross lines, we must keep track of any line-break
                                   * we encounter.
                                   */
                                  if (debugSymbols && expr[cursor] == '\n') {
                                      line++;
                                  }
  
                                  if (cursor == len) {
                                      throw new CompileException("unterminated block comment", expr, cursor);
                                  }
                                  if (expr[cursor] == '*' && isAt('/', 1)) {
                                      if ((cursor += 2) >= length) return null;
                                      skipWhitespace();
                                      start = cursor;
                                      break;
                                  }
                              }
  
                              if (debugSymbols) {
                                  getParserContext().setLineCount(line);
                              }
  
                              continue;
                          }
  
                      case'?':
                      case':':
                      case'^':
                      case'%': {
                          return createToken(expr, start, cursor++ + 1, fields);
                      }
  
                      case'(': {
                          cursor++;
  
                          boolean singleToken = true;
                          boolean lastWS = false;
  
                          skipWhitespace();
                          for (brace = 1; cursor < length && brace > 0; cursor++) {
                              switch (expr[cursor]) {
                                  case'(':
                                      brace++;
                                      break;
                                  case')':
                                      brace--;
                                      break;
                                  case'\'':
                                      cursor = captureStringLiteral('\'', expr, cursor, length);
                                      break;
                                  case'"':
                                      cursor = captureStringLiteral('\'', expr, cursor, length);
                                      break;
  
                                  case'i':
                                      if (isAt('n', 1) && isWhitespace(lookAhead(2))) {
                                          fields |= ASTNode.FOLD;
                                      }
                                      break;
                                  default:
                                      /**
                                       * Check to see if we should disqualify this current token as a potential
                                       * type-cast candidate.
                                       */
                                      if (lastWS || !isIdentifierPart(expr[cursor])) {
                                          singleToken = false;
                                      }
                                      else if (isWhitespace(expr[cursor])) {
                                          lastWS = true;
                                          skipWhitespace();
                                          cursor--;
                                      }
                              }
                          }
  
                          if (brace > 0) {
                              throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, cursor);
                          }
  
                          char[] _subset = null;
                          if (singleToken) {
                              String tokenStr = new String(_subset = subset(expr, trimRight(start + 1), trimLeft(cursor - 1) - (start + 1)));
  
                              if (getParserContext().hasImport(tokenStr)) {
                                  start = cursor;
                                  captureToEOS();
                                  return new TypeCast(expr, start, cursor, fields, getParserContext().getImport(tokenStr));
                              }
                              else if (LITERALS.containsKey(tokenStr)) {
                                  start = cursor;
                                  captureToEOS();
                                  return new TypeCast(expr, start, cursor, fields, (Class) LITERALS.get(tokenStr));
                              }
                              else {
                                  try {
                                      /**
                                       *
                                       *  take a stab in the dark and try and load the class
                                       */
                                      int _start = cursor;
                                      captureToEOS();
                                      return new TypeCast(expr, _start, cursor, fields, createClass(tokenStr));
  
                                  }
                                  catch (ClassNotFoundException e) {
                                      /**
                                       * Just fail through.
                                       */
                                  }
                              }
                          }
  
                          if ((fields & ASTNode.FOLD) != 0) {
                              if (cursor < length && expr[cursor] == '.') {
                                  cursor += 1;
                                  continue;
                              }
  
                              return createToken(expr, trimRight(start), cursor, ASTNode.FOLD);
                          }
  
                          if (_subset != null) {
                              return handleUnion(new Substatement(_subset, fields));
                          }
                          else {
                              return handleUnion(new Substatement(subset(expr, trimRight(start + 1), trimLeft(cursor - 1) - (start + 1)), fields));
                          }
                      }
  
                      case'}':
                      case']':
                      case')': {
                          throw new ParseException("unbalanced braces", expr, cursor);
                      }
  
                      case'>': {
                          if (expr[cursor + 1] == '>') {
                              if (expr[cursor += 2] == '>') cursor++;
                              return createToken(expr, start, cursor, fields);
                          }
                          else if (expr[cursor + 1] == '=') {
                              return createToken(expr, start, cursor += 2, fields);
                          }
                          else {
                              return createToken(expr, start, ++cursor, fields);
                          }
                      }
  
                      case'<': {
                          if (expr[++cursor] == '<') {
                              if (expr[++cursor] == '<') cursor++;
                              return createToken(expr, start, cursor, fields);
                          }
                          else if (expr[cursor] == '=') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'\'':
                          cursor = captureStringLiteral('\'', expr, cursor, length);
                          return new LiteralNode(handleStringEscapes(subset(expr, start + 1, cursor++ - start - 1)), String.class);
  
  
                      case'"':
                          cursor = captureStringLiteral('"', expr, cursor, length);
                          return new LiteralNode(handleStringEscapes(subset(expr, start + 1, cursor++ - start - 1)), String.class);
  
  
                      case'&': {
                          if (expr[cursor++ + 1] == '&') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'|': {
                          if (expr[cursor++ + 1] == '|') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'~':
                          if ((cursor - 1 < 0 || !isIdentifierPart(lookBehind(1)))
                                  && isDigit(expr[cursor + 1])) {
  
                              fields |= ASTNode.INVERT;
                              start++;
                              cursor++;
                              break;
                          }
                          else if (expr[cursor + 1] == '(') {
                              fields |= ASTNode.INVERT;
                              start = ++cursor;
                              continue;
                          }
                          else {
                              if (expr[cursor + 1] == '=') cursor++;
                              return createToken(expr, start, ++cursor, fields);
                          }
  
                      case'!': {
                          if (isIdentifierPart(expr[++cursor]) || expr[cursor] == '(') {
                              start = cursor;
                              fields |= ASTNode.NEGATION;
                              continue;
                          }
                          else if (expr[cursor] != '=')
                              throw new CompileException("unexpected operator '!'", expr, cursor, null);
                          else {
                              return createToken(expr, start, ++cursor, fields);
                          }
                      }
  
                      case'[':
                      case'{':
                          if (balancedCapture(expr[cursor]) == -1) {
                              if (cursor >= length) cursor--;
                              throw new CompileException("unbalanced brace: in inline map/list/array creation", expr, cursor);
                          }
  
                          if (cursor < (length - 1) && expr[cursor + 1] == '.') {
                              fields |= ASTNode.INLINE_COLLECTION;
                              cursor++;
                              continue;
                          }
  
                          return new InlineCollectionNode(expr, start, ++cursor, fields);
  
                      default:
                          cursor++;
                  }
          }
  
          return createPropertyToken(start, cursor);
      }
input: #vulnerable code 
                                  protected ASTNode nextToken() {
          /**
           * If the cursor is at the end of the expression, we have nothing more to do:
           * return null.
           */
          if (cursor >= length) {
              return null;
          }
          else if (!splitAccumulator.isEmpty()) {
              return lastNode = (ASTNode) splitAccumulator.pop();
          }
  
          int brace, start = cursor;
  
          /**
           * Because of parser recursion for sub-expression parsing, we sometimes need to remain
           * certain field states.  We do not reset for assignments, boolean mode, list creation or
           * a capture only mode.
           */
          fields = fields & (ASTNode.INLINE_COLLECTION | ASTNode.COMPILE_IMMEDIATE);
  
          boolean capture = false;
          boolean union = false;
  
          if (debugSymbols) {
              if (!lastWasLineLabel) {
                  if (getParserContext().getSourceFile() == null) {
                      throw new CompileException("unable to produce debugging symbols: source name must be provided.");
                  }
  
                  ParserContext pCtx = getParserContext();
  
                  line = pCtx.getLineCount();
  
                  int scan = cursor;
  
                  while (expr[scan] == '\n') {
                      scan++;
                      line++;
                  }
  
                  if (lastWasComment) {
                      line++;
                      lastWasComment = false;
                  }
  
                  pCtx.setLineCount(line);
  
                  if (!pCtx.isKnownLine(pCtx.getSourceFile(), line)) {
  
                      lastWasLineLabel = true;
  
                      pCtx.setLineAndOffset(line, cursor);
                      pCtx.addKnownLine(pCtx.getSourceFile(), line);
  
                      LineLabel ll = new LineLabel(pCtx.getSourceFile(), line);
                      if (pCtx.getFirstLineLabel() == null) pCtx.setFirstLineLabel(ll);
  
                      return lastNode = ll;
                  }
              }
              else {
                  lastWasComment = lastWasLineLabel = false;
              }
          }
  
          /**
           * Skip any whitespace currently under the starting point.
           */
          while (start < length && isWhitespace(expr[start])) start++;
  
          /**
           * From here to the end of the method is the core MVEL parsing code.  Fiddling around here is asking for
           * trouble unless you really know what you're doing.
           */
          for (cursor = start; cursor < length;) {
              if (isIdentifierPart(expr[cursor])) {
                  /**
                   * If the current character under the cursor is a valid
                   * part of an identifier, we keep capturing.
                   */
                  capture = true;
                  cursor++;
              }
              else if (capture) {
                  String t;
                  if (OPERATORS.containsKey(t = new String(expr, start, cursor - start))) {
                      switch (OPERATORS.get(t)) {
                          case NEW:
                              start = cursor + 1;
                              captureToEOT();
                              return new NewObjectNode(subArray(start, cursor), fields);
  
                          case ASSERT:
                              start = cursor + 1;
                              captureToEOS();
                              return new AssertNode(subArray(start, cursor--), fields);
  
                          case RETURN:
                              start = cursor + 1;
                              captureToEOS();
                              return new ReturnNode(subArray(start, cursor), fields);
  
                          case IF:
                              fields |= ASTNode.BLOCK_IF;
                              return captureCodeBlock();
  
                          case FOREACH:
                              fields |= ASTNode.BLOCK_FOREACH;
                              return captureCodeBlock();
  
                          case WITH:
                              fields |= ASTNode.BLOCK_WITH;
                              return captureCodeBlock();
  
                          case IMPORT:
                              start = cursor + 1;
                              captureToEOS();
                              ImportNode importNode = new ImportNode(subArray(start, cursor--), fields);
                              getParserContext().addImport(getSimpleClassName(importNode.getImportClass()), importNode.getImportClass());
                              return importNode;
  
                          case IMPORT_STATIC:
                              start = cursor + 1;
                              captureToEOS();
                              return new StaticImportNode(subArray(start, cursor--), fields);
                      }
                  }
  
                  /**
                   * If we *were* capturing a token, and we just hit a non-identifier
                   * character, we stop and figure out what to do.
                   */
                  skipWhitespace();
  
                  if (expr[cursor] == '(') {
                      fields |= ASTNode.METHOD;
  
                      /**
                       * If the current token is a method call or a constructor, we
                       * simply capture the entire parenthesized range and allow
                       * reduction to be dealt with through sub-parsing the property.
                       */
                      cursor++;
                      for (brace = 1; cursor < length && brace > 0;) {
                          switch (expr[cursor++]) {
                              case'(':
                                  brace++;
                                  break;
                              case')':
                                  brace--;
                                  break;
                              case'\'':
                                  cursor = captureStringLiteral('\'', expr, cursor, length) + 1;
                                  break;
  
                              case'"':
                                  cursor = captureStringLiteral('"', expr, cursor, length) + 1;
                                  break;
  
                          }
                      }
  
                      /**
                       * If the brace counter is greater than 0, we know we have
                       * unbalanced braces in the expression.  So we throw a
                       * optimize error now.
                       */
                      if (brace > 0)
                          throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, cursor);
                  }
  
                  /**
                   * If we encounter any of the following cases, we are still dealing with
                   * a contiguous token.
                   */
                  String name;
                  if (cursor < length) {
                      switch (expr[cursor]) {
                          case'+':
                              switch (lookAhead(1)) {
                                  case'+':
                                      ASTNode n = new PostFixIncNode(subArray(start, cursor), fields);
                                      cursor += 2;
                                      return n;
  
                                  case'=':
                                      name = new String(expr, start, trimLeft(cursor));
                                      start = cursor += 2;
                                      captureToEOS();
  
                                      if (union) {
                                          return new DeepAssignmentNode(subArray(start, cursor), fields, Operator.ADD, t);
                                      }
                                      else {
                                          return new AssignmentNode(subArray(start, cursor), fields, Operator.ADD, name);
                                      }
                              }
  
                              break;
  
                          case'-':
                              switch (lookAhead(1)) {
                                  case'-':
                                      ASTNode n = new PostFixDecNode(subArray(start, cursor), fields);
                                      cursor += 2;
                                      return n;
  
                                  case'=':
                                      name = new String(expr, start, trimLeft(cursor));
                                      start = cursor += 2;
                                      captureToEOS();
                                      return new AssignSub(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case'*':
                              if (isAt('=', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignMult(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case'/':
                              if (isAt('=', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignDiv(subArray(start, cursor), fields, name);
                              }
                              break;
  
                          case']':
                          case'[':
                              balancedCapture('[');
                              cursor++;
                              continue;
                          case'.':
                              union = true;
                              cursor++;
                              continue;
  
                          case'~':
                              if (isAt('=', 1)) {
                                  char[] stmt = subArray(start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOT();
                                  return new RegExMatch(stmt, fields, subArray(start, cursor));
                              }
                              break;
  
                          case'=':
                              if (isAt('+', 1)) {
                                  name = new String(expr, start, trimLeft(cursor));
                                  start = cursor += 2;
                                  captureToEOS();
                                  return new AssignAdd(subArray(start, cursor), fields, name);
                              }
  
                              if (greedy && !isAt('=', 1)) {
                                  cursor++;
  
                                  fields |= ASTNode.ASSIGN;
  
                                  skipWhitespace();
                                  captureToEOS();
  
                                  if (union) {
                                      return new DeepAssignmentNode(subArray(start, cursor), fields);
                                  }
                                  else if (lastWasIdentifier) {
  
                                      /**
                                       * Check for typing information.
                                       */
                                      if (lastNode.getLiteralValue() instanceof String) {
                                          if (getParserContext().hasImport((String) lastNode.getLiteralValue())) {
                                              lastNode.setLiteralValue(getParserContext().getImport((String) lastNode.getLiteralValue()));
                                              lastNode.setAsLiteral();
                                          }
                                          else {
                                              try {
                                                  /**
                                                   *  take a stab in the dark and try and load the class
                                                   */
                                                  lastNode.setLiteralValue(createClass((String) lastNode.getLiteralValue()));
                                                  lastNode.setAsLiteral();
                                              }
                                              catch (ClassNotFoundException e) {
                                                  /**
                                                   * Just fail through.
                                                   */
                                              }
                                          }
                                      }
  
                                      if (lastNode.isLiteral() && lastNode.getLiteralValue() instanceof Class) {
                                          lastNode.setDiscard(true);
  
                                          captureToEOS();
                                          return new TypedVarNode(subArray(start, cursor), fields, (Class)
                                                  lastNode.getLiteralValue());
                                      }
  
                                      throw new ParseException("unknown class: " + lastNode.getLiteralValue());
                                  }
                                  else {
                                      return new AssignmentNode(subArray(start, cursor), fields);
                                  }
                              }
                      }
                  }
  
                  /**
                   * Produce the token.
                   */
                  trimWhitespace();
  
                  return createToken(expr, start, cursor, fields);
              }
              else
                  switch (expr[cursor]) {
                      case'@': {
                          start++;
                          captureToEOT();
  
                          String interceptorName = new String(expr, start, cursor - start);
  
                          if (getParserContext().getInterceptors() == null || !getParserContext().getInterceptors().
                                  containsKey(interceptorName)) {
                              throw new CompileException("reference to undefined interceptor: " + interceptorName, expr, cursor);
                          }
  
                          return new InterceptorWrapper(getParserContext().getInterceptors().get(interceptorName), nextToken());
                      }
  
                      case'=':
                          return createToken(expr, start, (cursor += 2), fields);
  
                      case'-':
                          if (isAt('-', 1)) {
                              start = cursor += 2;
                              captureToEOT();
                              return new PreFixDecNode(subArray(start, cursor), fields);
                          }
                          else if ((cursor > 0 && !isWhitespace(lookBehind(1))) || !isDigit(lookAhead(1))) {
                              return createToken(expr, start, cursor++ + 1, fields);
                          }
                          else if ((cursor - 1) < 0 || (!isDigit(lookBehind(1))) && isDigit(lookAhead(1))) {
                              cursor++;
                              break;
                          }
  
                      case'+':
                          if (isAt('+', 1)) {
                              start = cursor += 2;
                              captureToEOT();
                              return new PreFixIncNode(subArray(start, cursor), fields);
                          }
                          return createToken(expr, start, cursor++ + 1, fields);
  
                      case'*':
                          if (isAt('*', 1)) {
                              cursor++;
                          }
                          return createToken(expr, start, cursor++ + 1, fields);
  
                      case';':
                          cursor++;
                          lastWasIdentifier = false;
                          return lastNode = new EndOfStatement();
  
                      case'#':
                      case'/':
                          if (isAt(expr[cursor], 1)) {
                              /**
                               * Handle single line comments.
                               */
                              while (cursor < length && expr[cursor] != '\n') cursor++;
  
                              if (debugSymbols) {
                                  line = getParserContext().getLineCount();
  
                                  skipWhitespaceWithLineAccounting();
  
                                  if (lastNode instanceof LineLabel) {
                                      getParserContext().getFirstLineLabel().setLineNumber(line);
                                  }
  
                                  lastWasComment = true;
  
                                  getParserContext().setLineCount(line);
                              }
                              else if (cursor < length) {
                                  skipWhitespace();
                              }
  
                              if ((start = cursor) >= length) return null;
  
                              continue;
                          }
                          else if (expr[cursor] == '/' && isAt('*', 1)) {
                              /**
                               * Handle multi-line comments.
                               */
                              int len = length - 1;
  
                              /**
                               * This probably seems highly redundant, but sub-compilations within the same
                               * source will spawn a new compiler, and we need to sync this with the
                               * parser context;
                               */
                              if (debugSymbols) {
                                  line = getParserContext().getLineCount();
                              }
  
                              while (true) {
                                  cursor++;
                                  /**
                                   * Since multi-line comments may cross lines, we must keep track of any line-break
                                   * we encounter.
                                   */
                                  if (debugSymbols && expr[cursor] == '\n') {
                                      line++;
                                  }
  
                                  if (cursor == len) {
                                      throw new CompileException("unterminated block comment", expr, cursor);
                                  }
                                  if (expr[cursor] == '*' && isAt('/', 1)) {
                                      if ((cursor += 2) >= length) return null;
                                      skipWhitespace();
                                      start = cursor;
                                      break;
                                  }
                              }
  
                              if (debugSymbols) {
                                  getParserContext().setLineCount(line);
                              }
  
                              continue;
                          }
  
                      case'?':
                      case':':
                      case'^':
                      case'%': {
                          return createToken(expr, start, cursor++ + 1, fields);
                      }
  
                      case'(': {
                          cursor++;
  
                          boolean singleToken = true;
                          boolean lastWS = false;
  
                          skipWhitespace();
                          for (brace = 1; cursor < length && brace > 0; cursor++) {
                              switch (expr[cursor]) {
                                  case'(':
                                      brace++;
                                      break;
                                  case')':
                                      brace--;
                                      break;
                                  case'\'':
                                      cursor = captureStringLiteral('\'', expr, cursor, length);
                                      break;
                                  case'"':
                                      cursor = captureStringLiteral('\'', expr, cursor, length);
                                      break;
  
                                  case'i':
                                      if (isAt('n', 1) && isWhitespace(lookAhead(2))) {
                                          fields |= ASTNode.FOLD;
                                      }
                                      break;
                                  default:
                                      /**
                                       * Check to see if we should disqualify this current token as a potential
                                       * type-cast candidate.
                                       */
                                      if (lastWS || isIdentifierPart(expr[cursor])) {
                                          singleToken = false;
                                      }
                                      else if (isWhitespace(expr[cursor])) {
                                          lastWS = true;
                                          skipWhitespace();
                                          cursor--;
                                      }
                              }
                          }
  
                          if (brace > 0) {
                              throw new CompileException("unbalanced braces in expression: (" + brace + "):", expr, cursor);
                          }
  
                          char[] _subset = null;
                          if (singleToken) {
                              String tokenStr = new String(_subset = subset(expr, trimRight(start + 1), trimLeft(cursor - 1) - (start + 1)));
  
                              if (getParserContext().hasImport(tokenStr)) {
                                  start = cursor;
                                  captureToEOS();
                                  return new TypeCast(expr, start, cursor, fields, getParserContext().getImport(tokenStr));
                              }
                              else if (LITERALS.containsKey(tokenStr)) {
                                  start = cursor;
                                  captureToEOS();
                                  return new TypeCast(expr, start, cursor, fields, (Class) LITERALS.get(tokenStr));
                              }
                              else {
                                  try {
                                      /**
                                       *
                                       *  take a stab in the dark and try and load the class
                                       */
                                      int _start = cursor;
                                      captureToEOS();
                                      return new TypeCast(expr, _start, cursor, fields, createClass(tokenStr));
  
                                  }
                                  catch (ClassNotFoundException e) {
                                      /**
                                       * Just fail through.
                                       */
                                  }
                              }
                          }
  
                          if ((fields & ASTNode.FOLD) != 0) {
                              if (cursor < length && expr[cursor] == '.') {
                                  cursor += 1;
                                  continue;
                              }
  
                              return createToken(expr, trimRight(start), cursor, ASTNode.FOLD);
                          }
  
                          if (_subset != null) {
                              return handleUnion(new Substatement(_subset, fields));
                          }
                          else {
                              return handleUnion(new Substatement(subset(expr, trimRight(start + 1), trimLeft(cursor - 1) - (start + 1)), fields));
                          }
                      }
  
                      case'}':
                      case']':
                      case')': {
                          throw new ParseException("unbalanced braces", expr, cursor);
                      }
  
                      case'>': {
                          if (expr[cursor + 1] == '>') {
                              if (expr[cursor += 2] == '>') cursor++;
                              return createToken(expr, start, cursor, fields);
                          }
                          else if (expr[cursor + 1] == '=') {
                              return createToken(expr, start, cursor += 2, fields);
                          }
                          else {
                              return createToken(expr, start, ++cursor, fields);
                          }
                      }
  
                      case'<': {
                          if (expr[++cursor] == '<') {
                              if (expr[++cursor] == '<') cursor++;
                              return createToken(expr, start, cursor, fields);
                          }
                          else if (expr[cursor] == '=') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'\'':
                          cursor = captureStringLiteral('\'', expr, cursor, length);
                          return new LiteralNode(handleStringEscapes(subset(expr, start + 1, cursor++ - start - 1)), String.class);
  
  
                      case'"':
                          cursor = captureStringLiteral('"', expr, cursor, length);
                          return new LiteralNode(handleStringEscapes(subset(expr, start + 1, cursor++ - start - 1)), String.class);
  
  
                      case'&': {
                          if (expr[cursor++ + 1] == '&') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'|': {
                          if (expr[cursor++ + 1] == '|') {
                              return createToken(expr, start, ++cursor, fields);
                          }
                          else {
                              return createToken(expr, start, cursor, fields);
                          }
                      }
  
                      case'~':
                          if ((cursor - 1 < 0 || !isIdentifierPart(lookBehind(1)))
                                  && isDigit(expr[cursor + 1])) {
  
                              fields |= ASTNode.INVERT;
                              start++;
                              cursor++;
                              break;
                          }
                          else if (expr[cursor + 1] == '(') {
                              fields |= ASTNode.INVERT;
                              start = ++cursor;
                              continue;
                          }
                          else {
                              if (expr[cursor + 1] == '=') cursor++;
                              return createToken(expr, start, ++cursor, fields);
                          }
  
                      case'!': {
                          if (isIdentifierPart(expr[++cursor]) || expr[cursor] == '(') {
                              start = cursor;
                              fields |= ASTNode.NEGATION;
                              continue;
                          }
                          else if (expr[cursor] != '=')
                              throw new CompileException("unexpected operator '!'", expr, cursor, null);
                          else {
                              return createToken(expr, start, ++cursor, fields);
                          }
                      }
  
                      case'[':
                      case'{':
                          if (balancedCapture(expr[cursor]) == -1) {
                              if (cursor >= length) cursor--;
                              throw new CompileException("unbalanced brace: in inline map/list/array creation", expr, cursor);
                          }
  
                          if (cursor < (length - 1) && expr[cursor + 1] == '.') {
                              fields |= ASTNode.INLINE_COLLECTION;
                              cursor++;
                              continue;
                          }
  
                          return new InlineCollectionNode(expr, start, ++cursor, fields);
  
                      default:
                          cursor++;
                  }
          }
  
          return createPropertyToken(start, cursor);
      } 
                              #location 508 
                              #vulnerability type THREAD_SAFETY_VIOLATION