/*******************************************************************************
* LastCalc - The last calculator you'll ever need
* Copyright (C) 2011, 2012 Uprizer Labs LLC
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Affero General Public License for more
* details.
******************************************************************************/
package com.lastcalc.engines;
import java.util.*;
import com.google.common.base.Function;
import com.google.common.collect.*;
import com.lastcalc.parsers.*;
public class KeywordParserPickerFactory extends ParserPickerFactory {
private static final long serialVersionUID = -2346529366052255216L;
private final Map<String, ParserSet> parsersMap;
Set<Parser> noKeywords = new ParserSet();
public KeywordParserPickerFactory(final Parser... parsers) {
this(Lists.newArrayList(parsers));
}
public KeywordParserPickerFactory(final Iterable<Parser> parsers) {
parsersMap = Maps.newHashMap();
for (final Parser parser : parsers) {
addParser(parser);
}
}
@Override
public void addParser(final Parser parser) {
List<ParserSet> addTo = null;
outer: for (final Object o : parser.getTemplate()) {
if (o instanceof String) {
ParserSet ll = parsersMap.get(o);
if (ll == null) {
ll = new ParserSet();
parsersMap.put((String) o, ll);
}
if (addTo == null || addTo.size() > 1 || addTo.get(0).size() > ll.size()) {
addTo = Collections.singletonList(ll);
}
} else if (o instanceof List) {
final List<?> ol = (List<?>) o;
final List<ParserSet> ma = Lists.newLinkedList();
for (final Object oi : ol) {
if (!(oi instanceof String)) {
continue outer;
}
ParserSet ll = parsersMap.get(oi);
if (ll == null) {
ll = new ParserSet();
parsersMap.put((String) oi, ll);
}
ma.add(ll);
}
if (addTo == null || ma.size() < addTo.size()) {
addTo = ma;
} else if (ma.size() == addTo.size()) {
int maTtl = 0;
for (final Set<Parser> ps : ma) {
maTtl += ps.size();
}
int atTtl = 0;
for (final Set<Parser> ps : addTo) {
atTtl += ps.size();
}
if (maTtl < atTtl) {
addTo = ma;
}
}
}
}
if (addTo == null || addTo.isEmpty()) {
noKeywords.add(parser);
} else {
for (final Set<Parser> sp : addTo) {
sp.add(parser);
}
}
}
@Override
public ParserPicker getPicker(final Map<Attempt, Integer> prevAttemptPos) {
return new KeywordParserPicker(prevAttemptPos, parsersMap, noKeywords);
}
@Override
public void teach(final Iterable<ParseStep> step) {
// Noop
}
public static class KeywordParserPicker extends ParserPicker {
private final Map<String, ParserSet> parsersMap;
private final Set<Parser> noKeywords;
public KeywordParserPicker(final Map<Attempt, Integer> prevAttemptPos,
final Map<String, ParserSet> parsersMap, final Set<Parser> noKeywords) {
super(prevAttemptPos);
this.parsersMap = parsersMap;
this.noKeywords = noKeywords;
}
@Override
public ParseStep pickNext(final ParserContext context, final ParseStep previous) {
Iterable<Parser> parsers = Iterables.concat(Iterables.transform(previous.result.output,
new Function<Object, Iterable<Parser>>() {
@Override
public Iterable<Parser> apply(final Object token) {
if ((!(token instanceof String)))
return Collections.emptyList();
final Set<Parser> parsers = parsersMap.get(token);
if (parsers == null)
return Collections.emptyList();
else
return parsers;
}
}));
parsers = Iterables.concat(parsers, noKeywords);
final ParseStep next = getNext(context, parsers, previous);
return next;
}
}
@Override
public Collection<Parser> getParsers() {
final Set<Parser> parsers = Sets.newHashSet();
for (final Set<Parser> ps : parsersMap.values()) {
parsers.addAll(ps);
}
return parsers;
}
}