All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.main.lombok.ast.grammar.ProfilerParseRunner Maven / Gradle / Ivy

Go to download

This is a very small fork of lombok.ast as some Android tools needed a few modifications. The normal repository for lombok.ast is here https://github.com/rzwitserloot/lombok.ast and our changes for 0.2.3 are in this pull request: https://github.com/rzwitserloot/lombok.ast/pull/8

The newest version!
/*
 * Copyright (C) 2010 The Project Lombok Authors.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package lombok.ast.grammar;

import java.util.Collection;
import java.util.List;
import java.util.TreeSet;

import lombok.Data;

import org.parboiled.BasicParseRunner;
import org.parboiled.MatchHandler;
import org.parboiled.MatcherContext;
import org.parboiled.Rule;

import com.google.common.collect.Lists;

/**
 * Like the {@code BasicParseRunner} but will also track statistics on the parse run which you can retrieve by calling {@link #getOverviewReport()}
 * or {@link #getExtendedReport(int)} after a parse run.
 */
public class ProfilerParseRunner extends BasicParseRunner {
	private ReportEntry rootReport;
	
	public ProfilerParseRunner(Rule rule, String input) {
		super(rule, input);
	}
	
	protected boolean runRootContext() {
		return runRootContext(new Handler());
	}
	
	protected boolean runRootContext(MatchHandler handler) {
		createRootContext(handler);
		return handler.matchRoot(rootContext);
	}
	
	protected void createRootContext(MatchHandler matchHandler) {
		rootContext = new MatcherContext(inputBuffer, parseErrors, matchHandler, rootMatcher);
	}
	
	/**
	 * Returns a string describing, in order of 'expensiveness', the top-level failed rule chains in the parse run.
	 */
	public String getOverviewReport() {
		TreeSet> topLevelFailed = new TreeSet>();
		fillReport(topLevelFailed, rootReport);
		StringBuilder out = new StringBuilder();
		for (ReportEntry entry : topLevelFailed) {
			if (entry.getSubSteps() < 100) break;
			out.append(formatReport(entry, false));
		}
		
		return out.toString();
	}
	
	/**
	 * Lists the work done by the most expensive failed rules.
	 * 
	 * First all failed rules are sorted according to how long they took, then, for each such rule,
	 * a string is produced listing it and all its child rules. These are returned.
	 * 
	 * @param topEntries Produce reports for the top {@code topEntries} most expensive failed rules.
	 *     a negative number means: All of them.
	 */
	public List getExtendedReport(int topEntries) {
		TreeSet> topLevelFailed = new TreeSet>();
		fillReport(topLevelFailed, rootReport);
		int count = topEntries;
		List result = Lists.newArrayList();
		StringBuilder out = new StringBuilder();
		for (ReportEntry entry : topLevelFailed) {
			if (count-- == 0) return result;
			out.setLength(0);
			fillExtendedReport(out, 0, entry);
			result.add(out.toString());
		}
		
		return result;
	}
	
	private static int countInnerNodes(ReportEntry entry) {
		int count = 1;
		for (ReportEntry child : entry.getChildren()) count += countInnerNodes(child);
		return count;
	}
	
	private void fillExtendedReport(StringBuilder out, int spaces, ReportEntry report) {
		for (int i = 0; i < spaces; i++) out.append(" ");
		out.append(formatReport(report, true));
		for (ReportEntry child : report.getChildren()) {
			fillExtendedReport(out, spaces + 1, child);
		}
	}
	
	private static String formatReport(ReportEntry report, boolean withSuccess) {
		return String.format("%s[%07d] %s\n",
				withSuccess ? (report.isSucceeded() ? "!" : " ") : "",
				report.getSubSteps(), report.getPath());
	}
	
	private void fillReport(Collection> failed, ReportEntry report) {
		if (!report.isSucceeded()) {
			failed.add(report);
		} else {
			for (ReportEntry child : report.getChildren()) {
				fillReport(failed, child);
			}
		}
	}
	
	@Data
	private static class ReportEntry implements Comparable> {
		private final String path;
		private boolean succeeded;
		private final List> children = Lists.newArrayList();
		private int subSteps = 0;
		
		@Override public int compareTo(ReportEntry o) {
			if (o.getSubSteps() < getSubSteps()) return -1;
			else if (o.getSubSteps() > getSubSteps()) return +1;
			
			if (System.identityHashCode(o) < System.identityHashCode(this)) return -1;
			if (System.identityHashCode(o) > System.identityHashCode(this)) return +1;
			return 0;
		}
	}
	
	public final class Handler implements MatchHandler {
		private final List> stack = Lists.newArrayList();
		
		public boolean matchRoot(MatcherContext rootContext) {
			return rootContext.runMatcher();
		}
		
		public boolean match(MatcherContext context) {
			String path = stack.isEmpty() ? "" : stack.get(stack.size() - 1).getPath();
			path += String.format("/%s[%d]", context.getMatcher().getLabel(), context.getCurrentIndex());
			ReportEntry report = new ReportEntry(path);
			stack.add(report);
			boolean result = context.getMatcher().match(context);
			report.setSucceeded(result);
			stack.remove(stack.size() -1);
			if (stack.isEmpty()) rootReport = report;
			else {
				ReportEntry parent = stack.get(stack.size() - 1);
				parent.getChildren().add(report);
				parent.setSubSteps(parent.getSubSteps() + 1 + report.getSubSteps());
			}
			return result;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy