// 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; } }