/* * Created on Apr 6, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu * (jactr.org) This library 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 2.1 of the License, * or (at your option) any later version. This library 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 this * library; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.io.antlr3.parser; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.TreeMap; import org.antlr.runtime.ANTLRInputStream; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.Lexer; import org.antlr.runtime.Parser; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.Token; import org.antlr.runtime.TokenSource; import org.antlr.runtime.TokenStream; import org.antlr.runtime.tree.CommonTree; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.io.antlr3.compiler.CompilationWarning; import org.jactr.io.parser.CanceledException; import org.jactr.io.parser.IModelParser; import org.jactr.io.parser.IParserImportDelegate; import org.jactr.io.parser.ITreeTracker; import org.jactr.io.parser.ParserImportDelegateFactory; /** * @author developer */ public abstract class AbstractModelParser implements IModelParser { static private final transient Log LOGGER = LogFactory .getLog(AbstractModelParser.class); static protected TokenStream NULL_TOKEN_STREAM = new TokenStream() { public Token LT( int arg0) { return null; } public Token get( int arg0) { return null; } public TokenSource getTokenSource() { return null; } public String toString( int arg0, int arg1) { return null; } public String toString( Token arg0, Token arg1) { return null; } public int LA( int arg0) { return 0; } public void consume() { } public int index() { return 0; } public int mark() { return 0; } public void release( int arg0) { } public void rewind() { } public void rewind( int arg0) { } public void seek( int arg0) { } public int size() { return 0; } public String getSourceName() { return null; } }; protected URL _url; protected CommonTree _modelTree; protected Collection<Exception> _errors; protected Collection<Exception> _warnings; protected IParserImportDelegate _delegate = ParserImportDelegateFactory .createDelegate((Object[]) null); protected CharStream _inputStream; protected Lexer _lexer; protected Parser _parser; protected Map<Integer, Collection<ITreeTracker>> _treeTrackers; /** * */ public AbstractModelParser() { super(); _lexer = createLexer(); _parser = createParser(); } synchronized public void addTreeTracker(ITreeTracker tracker) { if (_treeTrackers == null) _treeTrackers = new TreeMap<Integer, Collection<ITreeTracker>>(); for (int type : tracker.getRelevantTypes()) { Collection<ITreeTracker> trackers = _treeTrackers.get(type); if (trackers == null) { trackers = new ArrayList<ITreeTracker>(); _treeTrackers.put(type, trackers); } trackers.add(tracker); } } synchronized public void removeTreeTracker(ITreeTracker tracker) { if (_treeTrackers == null) return; for (int type : tracker.getRelevantTypes()) { Collection<ITreeTracker> trackers = _treeTrackers.get(type); if (trackers != null) { trackers.remove(tracker); if (trackers.size() == 0) _treeTrackers.remove(type); } } } synchronized public Collection<ITreeTracker> getTreeTrackers() { if (_treeTrackers == null) return Collections.EMPTY_LIST; HashSet<ITreeTracker> trackers = new HashSet<ITreeTracker>(); for (Collection<ITreeTracker> tracker : _treeTrackers.values()) trackers.addAll(tracker); return trackers; } synchronized public void delegate(CommonTree tree) { if (_treeTrackers == null) return; Collection<ITreeTracker> trackers = _treeTrackers.get(tree.getType()); if (trackers != null) for (ITreeTracker tracker : trackers) tracker.treeAssembled(tree); } public CommonTree getDocumentTree() { return _modelTree; } public Collection<Exception> getParseErrors() { if (_errors == null) return Collections.EMPTY_LIST; return Collections.unmodifiableCollection(_errors); } public Collection<Exception> getParseWarnings() { if (_warnings == null) return Collections.EMPTY_LIST; return Collections.unmodifiableCollection(_warnings); } public void setInput(URL url) throws IOException { setBaseURL(url); setInput(new ANTLRInputStream(url.openStream())); } public void setBaseURL(URL url) { _url = url; } public URL getBaseURL() { return _url; } /** * @see org.jactr.io.parser.IModelParser#getImportDelegate() */ public IParserImportDelegate getImportDelegate() { return _delegate; } /** * @see org.jactr.io.parser.IModelParser#setImportDelegate(org.jactr.io.parser.IParserImportDelegate) */ public void setImportDelegate(IParserImportDelegate delegate) { _delegate = delegate; } /** * @see org.jactr.io.parser.IModelParser#setInput(java.lang.String) */ public void setInput(String content) throws IOException { setInput(new ANTLRStringStream(content)); } public void setInput(CharStream antlrStream) { _inputStream = antlrStream; } public boolean parse() { reset(); getTreeTrackers(); _lexer.setCharStream(_inputStream); CommonTokenStream tokens = new CommonTokenStream(_lexer); _parser.setTokenStream(tokens); preParse(_parser); try { _modelTree = parseInternal(_parser); } catch (CanceledException pce) { throw pce; } catch (Exception re) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Error while parsing ", re); reportException(re, false); } finally { postParse(_parser); } if (_errors != null) return _errors.size() == 0; return true; } public void reset() { if (_lexer != null) _lexer.reset(); if (_parser != null) _parser.reset(); _modelTree = null; _errors = null; _warnings = null; _delegate.reset(); } public void dispose() { reset(); } abstract protected Lexer createLexer(); abstract protected Parser createParser(); abstract protected CommonTree parseInternal(Parser parser) throws RecognitionException; synchronized protected void preParse(Parser parser) { if (_treeTrackers == null) return; HashSet<ITreeTracker> fired = new HashSet<ITreeTracker>(); for (Map.Entry<Integer, Collection<ITreeTracker>> entry : _treeTrackers .entrySet()) for (ITreeTracker tracker : entry.getValue()) if (!fired.contains(tracker)) { fired.add(tracker); tracker.preParse(); } } synchronized protected void postParse(Parser parser) { if (_treeTrackers == null) return; boolean errors = _errors!=null && _errors.size()>0; HashSet<ITreeTracker> fired = new HashSet<ITreeTracker>(); for (Map.Entry<Integer, Collection<ITreeTracker>> entry : _treeTrackers .entrySet()) for (ITreeTracker tracker : entry.getValue()) if (!fired.contains(tracker)) { fired.add(tracker); tracker.postParse(errors); } } public void reportException(Exception e, boolean isLexing) { if (e instanceof RecognitionException) { RecognitionException re = (RecognitionException) e; String message = null; if (!isLexing) message = _parser.getErrorMessage(re, _parser.getTokenNames()); else message = _lexer.getErrorMessage(re, _lexer.getTokenNames()); if (message != null) { /* * create a new BS exception with a more meaningful message */ final String eMessage = message; RecognitionException nre = new RecognitionException() { @Override public String getMessage() { return eMessage; } }; nre.c = re.c; nre.charPositionInLine = re.charPositionInLine; nre.index = re.index; nre.line = re.line; nre.node = re.node; nre.token = re.token; e = nre; } } if (e instanceof CompilationWarning) { if (_warnings == null) _warnings = new ArrayList<Exception>(); _warnings.add(e); } else { if (_errors == null) _errors = new ArrayList<Exception>(); _errors.add(e); } } }