@Override
 public FlyweightCapableTreeStructure<LighterASTNode> parseContents(
     LighterLazyParseableNode chameleon) {
   final PsiBuilder builder = createBuilder(chameleon.getText());
   parse(builder);
   return builder.getLightTree();
 }
 public void parse(PsiBuilder builder) {
   final PsiBuilder.Marker root = builder.mark();
   PsiBuilder.Marker error = null;
   while (!builder.eof()) {
     final String token = builder.getTokenText();
     if ("?".equals(token)) error = builder.mark();
     builder.advanceLexer();
     if (error != null) {
       error.error("test error 2");
       error = null;
     }
   }
   root.done(this);
 }
  private static void doTest(
      @NonNls final String text, final Parser parser, @NonNls final String expected) {
    final PsiBuilder builder = createBuilder(text);
    final PsiBuilder.Marker rootMarker = builder.mark();
    parser.parse(builder);
    rootMarker.done(ROOT);

    // check light tree composition
    final FlyweightCapableTreeStructure<LighterASTNode> lightTree = builder.getLightTree();
    assertEquals(expected, DebugUtil.lightTreeToString(lightTree, false));
    // verify that light tree can be taken multiple times
    final FlyweightCapableTreeStructure<LighterASTNode> lightTree2 = builder.getLightTree();
    assertEquals(expected, DebugUtil.lightTreeToString(lightTree2, false));

    // check heavy tree composition
    final ASTNode root = builder.getTreeBuilt();
    assertEquals(expected, DebugUtil.nodeTreeToString(root, false));

    // check heavy vs. light tree merging
    final PsiBuilder builder2 = createBuilder(text);
    final PsiBuilder.Marker rootMarker2 = builder2.mark();
    parser.parse(builder2);
    rootMarker2.done(ROOT);
    DiffTree.diff(
        new ASTStructure(root),
        builder2.getLightTree(),
        new ShallowNodeComparator<ASTNode, LighterASTNode>() {
          @Override
          public ThreeState deepEqual(ASTNode oldNode, LighterASTNode newNode) {
            return ThreeState.UNSURE;
          }

          @Override
          public boolean typesEqual(ASTNode oldNode, LighterASTNode newNode) {
            return true;
          }

          @Override
          public boolean hashCodesEqual(ASTNode oldNode, LighterASTNode newNode) {
            return true;
          }
        },
        new DiffTreeChangeBuilder<ASTNode, LighterASTNode>() {
          @Override
          public void nodeReplaced(@NotNull ASTNode oldChild, @NotNull LighterASTNode newChild) {
            fail("replaced(" + oldChild + "," + newChild.getTokenType() + ")");
          }

          @Override
          public void nodeDeleted(@NotNull ASTNode oldParent, @NotNull ASTNode oldNode) {
            fail("deleted(" + oldParent + "," + oldNode + ")");
          }

          @Override
          public void nodeInserted(
              @NotNull ASTNode oldParent, @NotNull LighterASTNode newNode, int pos) {
            fail("inserted(" + oldParent + "," + newNode.getTokenType() + ")");
          }
        });
  }
 public void parse(PsiBuilder builder) {
   final PsiBuilder.Marker root = builder.mark();
   PsiBuilder.Marker nested = null;
   while (!builder.eof()) {
     final String token = builder.getTokenText();
     if ("[".equals(token) && nested == null) {
       nested = builder.mark();
     }
     builder.advanceLexer();
     if ("]".equals(token) && nested != null) {
       nested.collapse(myCHAMELEON_2);
       nested.precede().done(OTHER);
       nested = null;
       builder.error("test error 1");
     }
   }
   if (nested != null) nested.drop();
   root.done(this);
 }
 @Override
 public ASTNode parseContents(ASTNode chameleon) {
   final PsiBuilder builder = createBuilder(chameleon.getText());
   parse(builder);
   return builder.getTreeBuilt().getFirstChildNode();
 }
  private static void doFailTest(
      @NonNls final String text, final Parser parser, @NonNls final String expected) {
    final PrintStream std = System.err;
    //noinspection IOResourceOpenedButNotSafelyClosed
    System.setErr(new PrintStream(new NullStream()));
    try {
      try {
        ParserDefinition parserDefinition =
            new ParserDefinition() {
              @NotNull
              @Override
              public Lexer createLexer(Project project) {
                return null;
              }

              @Override
              public PsiParser createParser(Project project) {
                return null;
              }

              @Override
              public IFileElementType getFileNodeType() {
                return null;
              }

              @NotNull
              @Override
              public TokenSet getWhitespaceTokens() {
                return TokenSet.EMPTY;
              }

              @NotNull
              @Override
              public TokenSet getCommentTokens() {
                return TokenSet.EMPTY;
              }

              @NotNull
              @Override
              public TokenSet getStringLiteralElements() {
                return null;
              }

              @NotNull
              @Override
              public PsiElement createElement(ASTNode node) {
                return null;
              }

              @Override
              public PsiFile createFile(FileViewProvider viewProvider) {
                return null;
              }

              @Override
              public SpaceRequirements spaceExistanceTypeBetweenTokens(
                  ASTNode left, ASTNode right) {
                return null;
              }
            };
        final PsiBuilder builder =
            PsiBuilderFactory.getInstance()
                .createBuilder(parserDefinition, new MyTestLexer(), text);
        builder.setDebugMode(true);
        parser.parse(builder);
        builder.getLightTree();
        fail("should fail");
      } catch (AssertionError e) {
        assertEquals(expected, e.getMessage());
      }
    } finally {
      System.setErr(std);
    }
  }