@Nonnull
	private CompletableFuture<Result<List<ASTElement>>> parseAST() {
		// Nothing to parse
		if (editor.getText().isBlank()) return CompletableFuture.completedFuture(null);

		// Clear lint errors since we are running the linter again.
		if (problemTracking.removeByPhase(ProblemPhase.LINT))
			FxThreadUtil.run(editor::redrawParagraphGraphics);

		return CompletableFuture.supplyAsync(() -> {
			// Tokenize the current input.
			Result<List<Token>> tokenResult = pipeline.tokenize(editor.getText(), "<assembler>");

			// Process any errors and assign the latest token list.
			if (tokenResult.hasErr())
				processErrors(tokenResult.errors(), ProblemPhase.LINT);
			lastTokens = tokenResult.get();

			// Attempt to parse the token list into 'rough' AST.
			Result<List<ASTElement>> roughResult = pipeline.roughParse(lastTokens).ifOk(roughAst -> {
				lastRoughAst = roughAst;
			}).ifErr((partialAst, errors) -> {
				// We failed to parse the token list fully, but may have a partial result.
				eachChild(AssemblerAstConsumer.class, c -> c.consumeAst(partialAst, AstPhase.ROUGH_PARTIAL));
				lastPartialAst = partialAst;
				processErrors(errors, ProblemPhase.LINT);
			});

			// Attempt to complete parsing and transform the 'rough' AST into a 'concrete' AST.
			if (roughResult.isOk()) {
				return pipeline.concreteParse(roughResult.get()).ifOk(concreteAst -> {
					// The transform was a success.
					lastConcreteAst = concreteAst;
					if (tabCompleter != null) tabCompleter.setAst(concreteAst);
					eachChild(AssemblerAstConsumer.class, c -> c.consumeAst(concreteAst, AstPhase.CONCRETE));
				}).ifErr((partialAst, errors) -> {
					// The transform failed.
					lastPartialAst = partialAst;
					if (tabCompleter != null) tabCompleter.setAst(partialAst);
					eachChild(AssemblerAstConsumer.class, c -> c.consumeAst(partialAst, AstPhase.CONCRETE_PARTIAL));
					processErrors(errors, ProblemPhase.LINT);
				});
			} else {
				if (tabCompleter != null) tabCompleter.clearAst();
			}

			// Fall-back to rough AST.
			return roughResult;
		}).whenComplete((res, err) -> {
			if (err != null) {
				logger.error("Failed to parse assembler content", err);
				FxThreadUtil.run(() -> Animations.animateFailure(editor, 1000));
			}
		});
	}
Parse the current editor's text into AST.

@return Future of parse completion.
recaf-ui/src/main/java/software/coley/recaf/ui/pane/editing/assembler/AssemblerPane.java