// This file is part of AceWiki.
// Copyright 2008-2013, AceWiki developers.
//
// AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// AceWiki 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
// not, see http://www.gnu.org/licenses/.
package ch.uzh.ifi.attempto.acewiki.gf;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.base.Joiner;
import com.google.common.collect.Multimap;
import ch.uzh.ifi.attempto.base.ConcreteOption;
import ch.uzh.ifi.attempto.base.NextTokenOptions;
import ch.uzh.ifi.attempto.base.PredictiveParser;
import ch.uzh.ifi.attempto.base.SimpleConcreteOption;
import ch.uzh.ifi.attempto.base.SimpleNextTokenOptions;
import ch.uzh.ifi.attempto.gfservice.GfServiceException;
/**
* This is a predictive parser connecting to the JPGF implementation of GF.
*
* @author Kaarel Kaljurand
*/
public class GfPredictiveParser implements PredictiveParser {
private List<String> tokens = new ArrayList<String>();
private NextTokenOptions nextTokenOptions;
private GfGrammar gfGrammar;
private String language;
/**
* Creates a new parser object for the given language.
*
* @param gfGrammar The grammar object.
* @param language The language.
*/
public GfPredictiveParser(GfGrammar gfGrammar, String language) {
this.gfGrammar = gfGrammar;
this.language = language;
update();
}
private void update() {
// lazy parsing
nextTokenOptions = null;
}
public void addToken(String token) {
tokens.add(token);
update();
}
public void addTokens(List<String> tokens) {
this.tokens.addAll(tokens);
update();
}
public void removeToken() {
tokens.remove(tokens.size()-1);
update();
}
public void removeAllTokens() {
tokens.clear();
update();
}
public void setTokens(List<String> tokens) {
this.tokens.clear();
this.tokens.addAll(tokens);
update();
}
public List<String> getTokens() {
return tokens;
}
public int getTokenCount() {
return tokens.size();
}
public NextTokenOptions getNextTokenOptions() {
if (nextTokenOptions == null) {
Set<ConcreteOption> options = new HashSet<ConcreteOption>();
try {
Multimap<String, String> tokenToCats = gfGrammar.getTokenToCats(language);
Set<String> completions = gfGrammar.complete(tokens, language);
for (String s : completions) {
if (tokenToCats == null) {
options.add(new SimpleConcreteOption(s));
} else {
Collection<String> cats = tokenToCats.get(s);
if (cats.isEmpty()) {
options.add(new SimpleConcreteOption(s));
} else {
for (String c : cats) {
options.add(new SimpleConcreteOption(s, c));
}
}
}
}
nextTokenOptions = new SimpleNextTokenOptions(options);
} catch (GfServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return nextTokenOptions;
}
public boolean isPossibleNextToken(String token) {
return getNextTokenOptions().containsToken(token);
}
/**
* <p>TODO: one should distinguish between "complete" and "parsable".
* E.g. an ACE text is never complete, because one can always add another
* sentence creating another ACE text. An incomplete ACE can be parsable
* though, e.g. a one-sentence ACE text.</p>
*
* @return <code>true</code> iff the current text is parsable
*/
public boolean isComplete() {
try {
return ! gfGrammar.parse(Joiner.on(" ").join(tokens), language).isEmpty();
} catch (GfServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
public int getReference() {
return -1;
}
}