use of org.metaborg.util.time.Timer in project spoofax by metaborg.
the class ConstraintMultiFileAnalyzer method analyzeSemiIncremental.
private ISpoofaxAnalyzeResults analyzeSemiIncremental(Map<String, ISpoofaxParseUnit> changed, java.util.Set<String> removed, IMultiFileScopeGraphContext context, HybridInterpreter runtime, String strategy, IProgress progress, ICancel cancel) throws AnalysisException {
final NaBL2DebugConfig debugConfig = context.config().debug();
final Timer totalTimer = new Timer(true);
final AggregateTimer collectionTimer = new AggregateTimer();
final AggregateTimer solverTimer = new AggregateTimer();
final AggregateTimer finalizeTimer = new AggregateTimer();
final String globalSource = "";
final Function1<String, String> globalFresh = base -> context.unit(globalSource).fresh().fresh(base);
for (String input : removed) {
context.removeUnit(input);
}
final int n = changed.size();
final int w = context.units().size() / 2;
progress.setWorkRemaining(n + w + 1);
if (debugConfig.analysis() || debugConfig.files()) {
logger.info("Analyzing {} files in {}.", n, context.location());
}
final Collection<ISpoofaxAnalyzeUnit> results = Lists.newArrayList();
final Collection<ISpoofaxAnalyzeUnitUpdate> updateResults = Lists.newArrayList();
try {
// initial
InitialResult initialResult;
final Optional<ITerm> customInitial;
{
if (debugConfig.collection()) {
logger.info("Collecting initial constraints.");
}
if (context.initialResult().isPresent()) {
initialResult = context.initialResult().get();
customInitial = context.initialResult().flatMap(r -> r.getCustomResult());
} else {
collectionTimer.start();
try {
final ITerm globalAST = Actions.sourceTerm(globalSource, B.EMPTY_TUPLE);
ITerm initialResultTerm = doAction(strategy, Actions.analyzeInitial(globalSource, globalAST), context, runtime).orElseThrow(() -> new AnalysisException(context, "No initial result."));
initialResult = InitialResult.matcher().match(initialResultTerm).orElseThrow(() -> new AnalysisException(context, "Invalid initial results."));
customInitial = doCustomAction(strategy, Actions.customInitial(globalSource, globalAST), context, runtime);
initialResult = initialResult.withCustomResult(customInitial);
context.setInitialResult(initialResult);
} finally {
collectionTimer.stop();
}
}
if (debugConfig.collection()) {
logger.info("Initial constraints collected.");
}
}
// global parameters, that form the interface for a single unit
final java.util.Set<ITermVar> intfVars = Sets.newHashSet();
{
initialResult.getArgs().getParams().stream().forEach(param -> intfVars.addAll(param.getVars()));
initialResult.getArgs().getType().ifPresent(type -> intfVars.addAll(type.getVars()));
}
final SemiIncrementalMultiFileSolver solver = new SemiIncrementalMultiFileSolver(context.config().debug(), callExternal(runtime));
// global
ISolution initialSolution;
{
if (context.initialSolution().isPresent()) {
initialSolution = context.initialSolution().get();
} else {
try {
solverTimer.start();
final IProgress subprogress = progress.subProgress(1);
GraphSolution preSolution = solver.solveGraph(ImmutableBaseSolution.of(initialResult.getConfig(), initialResult.getConstraints(), PersistentUnifier.Immutable.of()), globalFresh, cancel, subprogress);
preSolution = solver.reportUnsolvedGraphConstraints(preSolution);
initialSolution = solver.solveIntra(preSolution, intfVars, null, globalFresh, cancel, subprogress);
if (debugConfig.resolution()) {
logger.info("Reduced file constraints to {}.", initialSolution.constraints().size());
}
} catch (SolverException e) {
throw new AnalysisException(context, e);
} finally {
solverTimer.stop();
}
context.setInitialSolution(initialSolution);
}
}
final java.util.Set<Scope> intfScopes = Sets.newHashSet();
{
initialResult.getArgs().getParams().stream().forEach(param -> Scope.matcher().match(param, initialSolution.unifier()).ifPresent(intfScopes::add));
}
// units
final Map<String, IStrategoTerm> astsByFile = Maps.newHashMap();
final Map<String, IMessage> failures = Maps.newHashMap();
final Multimap<String, IMessage> ambiguitiesByFile = HashMultimap.create();
for (Map.Entry<String, ISpoofaxParseUnit> input : changed.entrySet()) {
final String source = input.getKey();
final ISpoofaxParseUnit parseUnit = input.getValue();
final ITerm ast = strategoTerms.fromStratego(parseUnit.ast());
if (debugConfig.files()) {
logger.info("Analyzing {}.", source);
}
final IMultiFileScopeGraphUnit unit = context.unit(source);
unit.clear();
try {
UnitResult unitResult;
final Optional<ITerm> customUnit;
{
if (debugConfig.collection()) {
logger.info("Collecting constraints of {}.", source);
}
try {
collectionTimer.start();
final ITerm unitResultTerm = doAction(strategy, Actions.analyzeUnit(source, ast, initialResult.getArgs()), context, runtime).orElseThrow(() -> new AnalysisException(context, "No unit result."));
unitResult = UnitResult.matcher().match(unitResultTerm).orElseThrow(() -> new MetaborgException("Invalid unit results."));
final ITerm desugaredAST = unitResult.getAST();
customUnit = doCustomAction(strategy, Actions.customUnit(source, desugaredAST, customInitial.orElse(B.EMPTY_TUPLE)), context, runtime);
unitResult = unitResult.withCustomResult(customUnit);
final IStrategoTerm analyzedAST = strategoTerms.toStratego(desugaredAST);
astsByFile.put(source, analyzedAST);
ambiguitiesByFile.putAll(source, analysisCommon.ambiguityMessages(parseUnit.source(), parseUnit.ast()));
unit.setUnitResult(unitResult);
} finally {
collectionTimer.stop();
}
if (debugConfig.collection()) {
logger.info("Collected {} constraints of {}.", unitResult.getConstraints().size(), source);
}
}
{
final ISolution unitSolution;
if (debugConfig.resolution()) {
logger.info("Reducing {} constraints of {}.", unitResult.getConstraints().size(), source);
}
try {
solverTimer.start();
final Function1<String, String> fresh = base -> context.unit(source).fresh().fresh(base);
final IProgress subprogress = progress.subProgress(1);
GraphSolution preSolution = solver.solveGraph(ImmutableBaseSolution.of(initialResult.getConfig(), unitResult.getConstraints(), initialSolution.unifier()), fresh, cancel, subprogress);
preSolution = solver.reportUnsolvedGraphConstraints(preSolution);
unitSolution = solver.solveIntra(preSolution, intfVars, intfScopes, fresh, cancel, subprogress);
if (debugConfig.resolution()) {
logger.info("Reduced file constraints to {}.", unitSolution.constraints().size());
}
} catch (SolverException e) {
throw new AnalysisException(context, e);
} finally {
solverTimer.stop();
}
unit.setPartialSolution(unitSolution);
if (debugConfig.files() || debugConfig.resolution()) {
logger.info("Analyzed {}: {} errors, {} warnings, {} notes, {} unsolved constraints.", source, unitSolution.messages().getErrors().size(), unitSolution.messages().getWarnings().size(), unitSolution.messages().getNotes().size(), unitSolution.constraints().size());
}
}
} catch (MetaborgException e) {
logger.warn("Analysis of " + source + " failed.", e);
failures.put(source, MessageFactory.newAnalysisErrorAtTop(parseUnit.source(), "File analysis failed.", e));
}
}
// solve
final ISolution solution;
final List<Optional<ITerm>> customUnits = Lists.newArrayList();
{
final List<ISolution> partialSolutions = Lists.newArrayList();
for (IMultiFileScopeGraphUnit unit : context.units()) {
unit.partialSolution().ifPresent(partialSolutions::add);
unit.unitResult().map(UnitResult::getCustomResult).ifPresent(customUnits::add);
}
if (debugConfig.resolution()) {
logger.info("Solving {} partial solutions.", partialSolutions.size());
}
ISolution sol;
try {
solverTimer.start();
Function1<String, String> fresh = base -> context.unit(globalSource).fresh().fresh(base);
IMessageInfo message = ImmutableMessageInfo.of(MessageKind.ERROR, MessageContent.of(), Actions.sourceTerm(globalSource));
sol = solver.solveInter(initialSolution, partialSolutions, message, fresh, cancel, progress.subProgress(w));
sol = solver.reportUnsolvedConstraints(sol);
} catch (SolverException e) {
throw new AnalysisException(context, e);
} finally {
solverTimer.stop();
}
if (!sol.flowSpecSolution().controlFlowGraph().isEmpty()) {
logger.debug("CFG is not empty: calling FlowSpec dataflow solver");
sol = new FixedPoint().entryPoint(sol, getFlowSpecTransferFunctions(context.language()));
}
solution = sol;
context.setSolution(solution);
if (debugConfig.resolution()) {
logger.info("Project constraints solved.");
}
}
// final
FinalResult finalResult;
final Optional<ITerm> customFinal;
final Optional<CustomSolution> customSolution;
{
if (debugConfig.analysis()) {
logger.info("Finalizing project analysis.");
}
finalizeTimer.start();
try {
ITerm finalResultTerm = doAction(strategy, Actions.analyzeFinal(globalSource), context, runtime).orElseThrow(() -> new AnalysisException(context, "No final result."));
finalResult = FinalResult.matcher().match(finalResultTerm, solution.unifier()).orElseThrow(() -> new AnalysisException(context, "Invalid final results."));
customFinal = doCustomAction(strategy, Actions.customFinal(globalSource, customInitial.orElse(B.EMPTY_TUPLE), Optionals.filter(customUnits)), context, runtime);
finalResult = finalResult.withCustomResult(customFinal);
context.setFinalResult(finalResult);
customSolution = customFinal.flatMap(cs -> CustomSolution.matcher().match(cs, solution.unifier()));
customSolution.ifPresent(cs -> context.setCustomSolution(cs));
} finally {
finalizeTimer.stop();
}
if (debugConfig.analysis()) {
logger.info("Project analysis finalized.");
}
}
// errors
{
if (debugConfig.analysis()) {
logger.info("Processing project messages.");
}
Messages.Transient messageBuilder = Messages.Transient.of();
messageBuilder.addAll(Messages.unsolvedErrors(solution.constraints()));
messageBuilder.addAll(solution.messages().getAll());
customSolution.map(CustomSolution::getMessages).map(IMessages::getAll).ifPresent(messageBuilder::addAll);
IMessages messages = messageBuilder.freeze();
IRelation3.Transient<String, MessageSeverity, IMessage> messagesByFile = HashTrieRelation3.Transient.of();
messagesByFile(failures.values(), messagesByFile, context);
messagesByFile(messages(messages.getAll(), solution.unifier(), context, context.location()), messagesByFile, context);
// precondition: the messagesByFile should not contain any files that do not have corresponding units
for (IMultiFileScopeGraphUnit unit : context.units()) {
final String source = unit.resource();
final java.util.Set<IMessage> fileMessages = messagesByFile.get(source).stream().map(Map.Entry::getValue).collect(Collectors2.toHashSet());
if (changed.containsKey(source)) {
fileMessages.addAll(ambiguitiesByFile.get(source));
final boolean valid = !failures.containsKey(source);
final boolean success = valid && messagesByFile.get(source, MessageSeverity.ERROR).isEmpty();
final IStrategoTerm analyzedAST = astsByFile.get(source);
results.add(unitService.analyzeUnit(changed.get(source), new AnalyzeContrib(valid, success, analyzedAST != null, analyzedAST, fileMessages, -1), context));
} else {
try {
final FileObject file = context.location().resolveFile(source);
updateResults.add(unitService.analyzeUnitUpdate(file, new AnalyzeUpdateData(fileMessages), context));
} catch (IOException ex) {
logger.error("Could not resolve {} to update messages", source);
}
}
messagesByFile.remove(source);
}
if (!messagesByFile.keySet().isEmpty()) {
logger.error("Found messages for unanalyzed files {}", messagesByFile.keySet());
}
if (debugConfig.analysis() || debugConfig.files() || debugConfig.resolution()) {
logger.info("Analyzed {} files: {} errors, {} warnings, {} notes.", n, messages.getErrors().size(), messages.getWarnings().size(), messages.getNotes().size());
}
}
} catch (InterruptedException e) {
logger.debug("Analysis was interrupted.");
} finally {
totalTimer.stop();
}
final ConstraintDebugData debugData = new ConstraintDebugData(totalTimer.stop(), collectionTimer.total(), solverTimer.total(), finalizeTimer.total());
if (debugConfig.analysis()) {
logger.info("{}", debugData);
}
return new SpoofaxAnalyzeResults(results, updateResults, context, debugData);
}
use of org.metaborg.util.time.Timer in project spoofax by metaborg.
the class StrategoAnalyzer method analyze.
private ISpoofaxAnalyzeUnit analyze(ISpoofaxParseUnit input, IContext context, HybridInterpreter runtime, String strategy, ITermFactory termFactory) throws AnalysisException {
final FileObject source = input.source();
final IStrategoString contextPath = strategoCommon.locationTerm(context.location());
final IStrategoString resourcePath = strategoCommon.resourceTerm(source, context.location());
final IStrategoTuple inputTerm = termFactory.makeTuple(input.ast(), resourcePath, contextPath);
try {
logger.trace("Analysing {}", source);
final Timer timer = new Timer(true);
final IStrategoTerm resultTerm = strategoCommon.invoke(runtime, inputTerm, strategy);
final long duration = timer.stop();
if (resultTerm == null) {
logger.trace("Analysis for {} failed", source);
return result(analysisCommon.analysisFailedMessage(runtime), input, context, null, duration);
} else if (!(resultTerm instanceof IStrategoTuple)) {
logger.trace("Analysis for {} has unexpected result, not a tuple", source);
final String message = logger.format("Unexpected results from analysis {}", resultTerm);
return result(message, input, context, null, duration);
} else if (resultTerm.getSubtermCount() == 4) {
logger.trace("Analysis for {} done", source);
return result(resultTerm, input, context, duration);
} else if (resultTerm.getSubtermCount() == 3) {
logger.trace("Analysis for {} done", source);
return resultNoAst(resultTerm, input, context, duration);
} else {
logger.trace("Analysis for {} has unexpected result; tuple with more than 4 or less than 2 elements", source);
final String message = logger.format("Unexpected results from analysis {}", resultTerm);
return result(message, input, context, null, duration);
}
} catch (MetaborgException e) {
final String message = logger.format("Analysis for {} failed", source);
logger.trace(message, e);
throw new AnalysisException(context, message, e);
}
}
use of org.metaborg.util.time.Timer in project spoofax by metaborg.
the class StrategoTransformer method transform.
private <I extends IUnit> ISpoofaxTransformUnit<I> transform(I input, IContext context, TransformActionContrib actionContribution, FileObject source, IStrategoTerm term, ITransformConfig config) throws TransformException {
final FileObject location = context.location();
final ILanguageComponent component = actionContribution.contributor;
final TransformAction action = action(actionContribution.action);
// Get input term
final IStrategoTerm inputTerm = common.builderInputTerm(term, source, location);
// Get Stratego runtime
final HybridInterpreter runtime;
try {
runtime = strategoRuntimeService.runtime(component, context, true);
} catch (MetaborgException e) {
throw new TransformException("Transformation failed unexpectedly; cannot get Stratego interpreter", e);
}
// Transform
logger.debug("Transforming {} with '{}'", source, action.name);
final Timer timer = new Timer(true);
final IStrategoTerm outputTerm;
try {
outputTerm = common.invoke(runtime, inputTerm, action.strategy);
} catch (MetaborgException e) {
throw new TransformException(e.getMessage(), e.getCause());
}
final long duration = timer.stop();
if (outputTerm == null) {
final String message = logger.format("Invoking Stratego strategy {} failed", action.strategy);
throw new TransformException(message);
}
// Get the result and, if allowed and required, write to file
List<TransformOutput> outputs;
IStrategoTerm resultTerm;
if (outputTerm.getSubtermCount() == 2 && (outputTerm instanceof IStrategoTuple)) {
final IStrategoTerm resourceTerm = outputTerm.getSubterm(0);
final IStrategoTerm contentTerm = outputTerm.getSubterm(1);
try {
if (resourceTerm instanceof IStrategoString) {
resultTerm = contentTerm;
outputs = Lists.newArrayList(output(resourceTerm, contentTerm, location, config));
} else if (resourceTerm instanceof IStrategoList) {
if (!(contentTerm instanceof IStrategoList) || resourceTerm.getSubtermCount() != contentTerm.getSubtermCount()) {
logger.error("List of terms does not match list of file names, cannot write to file.");
resultTerm = null;
outputs = Collections.emptyList();
} else {
outputs = Lists.newArrayListWithExpectedSize(resourceTerm.getSubtermCount());
for (int i = 0; i < resourceTerm.getSubtermCount(); i++) {
outputs.add(output(resourceTerm.getSubterm(i), contentTerm.getSubterm(i), location, config));
}
resultTerm = resourceTerm.getSubtermCount() == 1 ? resourceTerm.getSubterm(0) : null;
}
} else {
logger.error("First term of result tuple {} is neither a string, nor a list, cannot write output file", resourceTerm);
resultTerm = null;
outputs = Collections.emptyList();
}
} catch (MetaborgException ex) {
resultTerm = null;
outputs = Collections.emptyList();
}
} else {
resultTerm = outputTerm;
outputs = Collections.emptyList();
}
// Open editor
if (action.flags.openEditor) {
List<FileObject> resources = Lists.newArrayListWithExpectedSize(outputs.size());
for (TransformOutput output : outputs) {
if (output.resource != null) {
resources.add(output.resource);
}
}
editorRegistry.open(resources, context.project());
}
// Return result
final TransformContrib contrib = new TransformContrib(resultTerm != null || !Iterables.isEmpty(outputs), true, resultTerm, outputs, Iterables2.<IMessage>empty(), duration);
return unitService.transformUnit(input, contrib, context, actionContribution);
}
use of org.metaborg.util.time.Timer in project spoofax by metaborg.
the class JSGLR1I method parse.
public ParseContrib parse(@Nullable JSGLRParserConfiguration parserConfig) throws IOException {
if (parserConfig == null) {
parserConfig = new JSGLRParserConfiguration();
}
final String fileName = resource != null ? resource.getName().getURI() : null;
final JSGLRParseErrorHandler errorHandler = new JSGLRParseErrorHandler(this, resource, getParseTable(config.getParseTableProvider()).hasRecovers());
final Timer timer = new Timer(true);
SGLRParseResult result;
try {
// should throw a fatal, or return a non-null result
result = actuallyParse(input, fileName, parserConfig);
assert result != null;
} catch (SGLRException | InterruptedException e) {
result = null;
errorHandler.setRecoveryFailed(parserConfig.recovery);
errorHandler.processFatalException(new NullTokenizer(input, fileName), e);
}
final long duration = timer.stop();
final IStrategoTerm ast;
if (result != null) {
// No fatals occurred, so either parsing succeeded or recovery succeeded
ast = (IStrategoTerm) result.output;
if (ast == null) {
// so we have nothing to do
assert parser.getTreeBuilder() instanceof NullTreeBuilder;
} else {
// in case recovery was required, collect the recoverable errors
errorHandler.setRecoveryFailed(false);
errorHandler.gatherNonFatalErrors(ast);
if (resource != null) {
SourceAttachment.putSource(ast, resource);
}
}
} else {
ast = null;
}
final boolean hasAst = ast != null;
final Iterable<IMessage> messages = errorHandler.messages();
final boolean hasErrors = MessageUtils.containsSeverity(messages, MessageSeverity.ERROR);
return new ParseContrib(hasAst, hasAst && !hasErrors, ast, messages, duration);
}
use of org.metaborg.util.time.Timer in project spoofax by metaborg.
the class JSGLR2I method parse.
public ParseContrib parse(@Nullable JSGLRParserConfiguration parserConfig) throws IOException {
if (parserConfig == null) {
parserConfig = new JSGLRParserConfiguration();
}
final String fileName = resource != null ? resource.getName().getURI() : null;
String startSymbol = getOrDefaultStartSymbol(parserConfig);
final Timer timer = new Timer(true);
final IStrategoTerm ast = parser.parse(input, fileName, startSymbol);
final long duration = timer.stop();
final boolean hasAst = ast != null;
final boolean hasErrors = ast == null;
final Iterable<IMessage> messages;
if (hasErrors)
messages = Collections.singletonList(MessageFactory.newParseErrorAtTop(resource, "Invalid syntax", null));
else
messages = Collections.emptyList();
return new ParseContrib(hasAst, hasAst && !hasErrors, ast, messages, duration);
}
Aggregations