Coverage Report - net.sf.jmatchparser.template.engine.ParserImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ParserImpl
89%
98/110
78%
40/51
3,105
ParserImpl$1
100%
1/1
N/A
3,105
 
 1  
 /*
 2  
  * Copyright (c) 2006 - 2011 Michael Schierl
 3  
  * All rights reserved.
 4  
  * 
 5  
  * This program is free software: you can redistribute it and/or modify
 6  
  * it under the terms of the GNU General Public License as published by
 7  
  * the Free Software Foundation, either version 2 of the License, or
 8  
  * (at your option) any later version.
 9  
  * 
 10  
  * This program is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  
  * GNU General Public License for more details.
 14  
  * 
 15  
  * You should have received a copy of the GNU General Public License
 16  
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17  
  */
 18  
 package net.sf.jmatchparser.template.engine;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.io.PrintStream;
 22  
 import java.util.ArrayList;
 23  
 import java.util.HashMap;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 
 27  
 import net.sf.jmatchparser.template.CallbackFunction;
 28  
 import net.sf.jmatchparser.template.ParserException;
 29  
 import net.sf.jmatchparser.template.engine.operation.Operation;
 30  
 import net.sf.jmatchparser.template.engine.operation.Operation.OperationResult;
 31  
 
 32  
 import net.sf.jmatchparser.template.engine.template.MatchTemplateImpl;
 33  
 import org.w3c.dom.Element;
 34  
 
 35  
 public class ParserImpl {
 36  
 
 37  188
         private CharSequence file = null;
 38  188
         private StringBuilder writeBuffer = new StringBuilder();
 39  188
         private String parserName = null;
 40  
 
 41  188
         private List<ParserState> queuedStates = new ArrayList<ParserState>();
 42  
         private final MatchTemplateImpl template;
 43  188
         private Map<String, CallbackFunction> callbacks = new HashMap<String, CallbackFunction>();
 44  188
         private ParserState sideEffectState = null;
 45  188
         private PrintStream debugStream = System.out;
 46  
 
 47  188
         public ParserImpl(MatchTemplateImpl template) {
 48  188
                 this.template = template;
 49  188
                 queuedStates.add(new ParserState(this));
 50  188
                 DefaultCallbackFunctions.addTo(this);
 51  188
         }
 52  
 
 53  
         public void setLocal(String name, String value) {
 54  1
                 if (file != null)
 55  0
                         throw new IllegalStateException("Parser has already been used");
 56  1
                 queuedStates.get(0).setLocal(name, value);
 57  1
         }
 58  
 
 59  
         public void setParserName(String parserName) {
 60  1
                 this.parserName = parserName;
 61  1
         }
 62  
 
 63  
         public void parse(CharSequence file, Element target) throws ParserException, IOException {
 64  188
                 if (this.file != null)
 65  0
                         throw new IllegalStateException("Parser has already been used");
 66  188
                 this.file = file;
 67  188
                 ParserState finalState = run();
 68  164
                 finalState.applyXMLActions(target);
 69  164
                 if (finalState.getCallStack() != null)
 70  0
                         throw new IllegalStateException("Pending return calls");
 71  164
                 if (finalState.getCoveredOperations() != null)
 72  1
                         template.addCoveredOperations(finalState.getCoveredOperations());
 73  164
         }
 74  
 
 75  
         private ParserState run() throws ParserException, IOException {
 76  188
                 int lastFailOffset = -1;
 77  188
                 List<String> lastFailTemplatePositions = new ArrayList<String>();
 78  188
                 List<String> sideEffectBlockedTemplatePositions = new ArrayList<String>();
 79  188
                 ParserState finishedState = null;
 80  924
                 while (queuedStates.size() > 0) {
 81  736
                         ParserState current = queuedStates.remove(0);
 82  736
                         OperationResult opres = OperationResult.CONTINUE;
 83  4685
                         while (opres == OperationResult.CONTINUE) {
 84  3949
                                 int ip = current.getNextInstructionAndIncrement();
 85  3949
                                 Operation op = template.getOperation(ip);
 86  
                                 try {
 87  3949
                                         opres = op.execute(current);
 88  0
                                 } catch (RuntimeException ex) {
 89  0
                                         throw new RuntimeException("Cannot execute operation at template position:\n\t" + op.getTemplatePosition(), ex);
 90  3949
                                 }
 91  3949
                                 if (opres == null)
 92  0
                                         throw new RuntimeException(op.getClass().toString() + " returned invalid operation result");
 93  1
                                 switch (opres) {
 94  
                                 case CONTINUE:
 95  
                                         // everything fine
 96  3203
                                         break;
 97  
                                 case NEXTPASS:
 98  10
                                         lastFailOffset = -1;
 99  10
                                         lastFailTemplatePositions.clear();
 100  10
                                         sideEffectBlockedTemplatePositions.clear();
 101  10
                                         opres = OperationResult.CONTINUE;
 102  10
                                         break;
 103  
                                 case DIE:
 104  53
                                         if (queuedStates.size() == 0)
 105  0
                                                 throw new RuntimeException("Last state died");
 106  
                                         break;
 107  
                                 case FAIL_BLOCKED:
 108  2
                                         sideEffectBlockedTemplatePositions.add(op.getTemplatePosition());
 109  
                                         // fall through
 110  
                                 case FAIL:
 111  519
                                         if (current.getOffset() > lastFailOffset) {
 112  208
                                                 lastFailOffset = current.getOffset();
 113  208
                                                 lastFailTemplatePositions.clear();
 114  
                                         }
 115  519
                                         if (current.getOffset() == lastFailOffset) {
 116  298
                                                 String cmd = op.getTemplatePosition();
 117  298
                                                 if (!lastFailTemplatePositions.contains(cmd)) {
 118  276
                                                         lastFailTemplatePositions.add(cmd);
 119  
                                                 }
 120  298
                                         }
 121  
                                         break;
 122  
                                 case FINISHED:
 123  164
                                         if (finishedState != null) {
 124  0
                                                 throw new IOException("Multiple paths finished successfully.");
 125  
                                         }
 126  164
                                         finishedState = current;
 127  
                                         break;
 128  
                                 }
 129  3949
                         }
 130  736
                 }
 131  188
                 if (finishedState == null) {
 132  24
                         if (lastFailOffset == -1)
 133  0
                                 throw new RuntimeException("No fail offset recorded!");
 134  24
                         StringBuilder sb = new StringBuilder();
 135  24
                         sb.append("Could not parse file" + (getParserName() == null ? "" : " '" + getParserName() + "'") + ". Template position(s):");
 136  24
                         for (String templatePosition : lastFailTemplatePositions) {
 137  27
                                 sb.append("\n\t" + templatePosition);
 138  
                         }
 139  24
                         if (sideEffectBlockedTemplatePositions.size() > 0) {
 140  1
                                 sb.append("\nSide effects blocked:");
 141  1
                                 for (String templatePosition : sideEffectBlockedTemplatePositions) {
 142  2
                                         sb.append("\n\t" + templatePosition);
 143  
                                 }
 144  
                         }
 145  24
                         sb.append("\nNext 1K to parse:\n\t");
 146  24
                         sb.append(getFile().subSequence(lastFailOffset, Math.min(getFile().length(), lastFailOffset + 1024)).toString().replace("\n", "\n\t"));
 147  24
                         throw new ParserException(sb.toString());
 148  
                 }
 149  164
                 return finishedState;
 150  
         }
 151  
 
 152  
         public CharSequence getFile() {
 153  2368
                 return file;
 154  
         }
 155  
 
 156  
         public String getBuffer() {
 157  208
                 String result = writeBuffer.toString();
 158  208
                 writeBuffer.setLength(0);
 159  208
                 return result;
 160  
         }
 161  
 
 162  
         public void writeBuffer(String text) {
 163  24
                 if (hasQueuedStates())
 164  0
                         throw new RuntimeException("There are queued states!");
 165  24
                 writeBuffer.append(text);
 166  24
         }
 167  
 
 168  
         public MatchTemplateImpl getTemplate() {
 169  263
                 return template;
 170  
         }
 171  
 
 172  
         public boolean hasQueuedStates() {
 173  496
                 return queuedStates.size() > 0;
 174  
         }
 175  
 
 176  
         public void enqueueState(ParserState toEnqueue) {
 177  548
                 queuedStates.add(toEnqueue);
 178  548
         }
 179  
 
 180  
         protected void setFile(ParserState current, CharSequence newFile) {
 181  10
                 if (hasQueuedStates())
 182  0
                         throw new RuntimeException("There are queued states!");
 183  10
                 if (current.getOffset() != 0)
 184  0
                         throw new RuntimeException("Some text has already been parsed:" + current.getOffset());
 185  10
                 file = newFile;
 186  10
         }
 187  
 
 188  
         public void addCallback(String name, CallbackFunction function) {
 189  1129
                 callbacks.put(name, function);
 190  1129
         }
 191  
 
 192  
         public CallbackFunction getCallback(String name) {
 193  41
                 return callbacks.get(name);
 194  
         }
 195  
 
 196  
         public String getParserName() {
 197  24
                 return parserName;
 198  
         }
 199  
 
 200  
         public ParserState getSideEffectState() {
 201  60
                 return sideEffectState;
 202  
         }
 203  
 
 204  
         public void setSideEffectState(ParserState sideEffectState) {
 205  4
                 this.sideEffectState = sideEffectState;
 206  4
         }
 207  
 
 208  
         public PrintStream getDebugStream() {
 209  14
                 return debugStream;
 210  
         }
 211  
 
 212  
         public void setDebugStream(PrintStream debugStream) {
 213  1
                 this.debugStream = debugStream;
 214  1
         }
 215  
 }