001 /*
002 * SourceInfo.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Mark A. Greenwood, 08/12/2010
013 *
014 */
015
016 package gate.jape;
017
018 import gate.util.Strings;
019
020 import java.util.ArrayList;
021 import java.util.List;
022
023 /**
024 * A simple class to store and use the mapping between Java and Jape
025 * source code for error reporting.
026 */
027 public class SourceInfo {
028
029 private List<BlockInfo> blocks = new ArrayList<BlockInfo>();
030
031 private String className = null;
032
033 private String phaseName = null;
034
035 private String sectionName = null;
036
037 public SourceInfo(String className, String phaseName, String sectionName) {
038 this.className = className;
039 this.phaseName = phaseName;
040 this.sectionName = sectionName;
041 }
042
043 public String addBlock(String previousCode, String codeBlock) {
044 if(!codeBlock.startsWith(" // JAPE Source:")) return codeBlock;
045
046 String info = codeBlock.substring(18, codeBlock.indexOf("\n")).trim();
047 String code = codeBlock.substring(codeBlock.indexOf("\n") + 1);
048
049 String japeURL = info.substring(0, info.lastIndexOf(":"));
050 int lineNumber = Integer
051 .parseInt(info.substring(info.lastIndexOf(":") + 1));
052
053 int startLine = previousCode.split("\n").length + 1;
054 int endLine = startLine + code.split("\n").length;
055
056 int startOffset = previousCode.length();
057 int endOffset = previousCode.length() + code.length();
058
059 blocks.add(new BlockInfo(japeURL, lineNumber, startLine, endLine,
060 startOffset, endOffset));
061
062 return code;
063 }
064
065 public String getSource(String source, int javaLineNumber) {
066 for(BlockInfo info : blocks) {
067 if(info.contains(javaLineNumber)) {
068 return info.getSource(source, info.getJapeLineNumber(javaLineNumber));
069 }
070 }
071
072 return "";
073 }
074
075 public StackTraceElement getStackTraceElement(int javaLineNumber) {
076 for(BlockInfo info : blocks) {
077 StackTraceElement japeSTE = info.getStackTraceElement(javaLineNumber);
078
079 if(japeSTE != null) return japeSTE;
080 }
081
082 return null;
083 }
084
085 /**
086 * Enhances a Throwable by replacing mentions of Java code inside a
087 * Jape RhsAction with a reference to the original Jape source where
088 * available.
089 *
090 * @param t the Throwable to enhance with Jape source information
091 */
092 public void enhanceTheThrowable(Throwable t) {
093 if(t.getCause() != null) {
094 enhanceTheThrowable(t.getCause());
095 }
096
097 List<StackTraceElement> stack = new ArrayList<StackTraceElement>();
098
099 for(StackTraceElement ste : t.getStackTrace()) {
100 if(ste.getClassName().equals(className)) {
101
102 StackTraceElement japeSTE = null;
103
104 if(ste.getLineNumber() >= 0) {
105 for(BlockInfo info : blocks) {
106 japeSTE = info.getStackTraceElement(ste.getLineNumber());
107
108 if(japeSTE != null) break;
109 }
110 }
111 else {
112 // this will happen if we are running from a
113 // serialised jape grammar as we don't keep the
114 // source info
115 japeSTE = new StackTraceElement(phaseName, sectionName, null, -1);
116 }
117
118 stack.add(japeSTE != null ? japeSTE : ste);
119 }
120 else {
121 stack.add(ste);
122 }
123 }
124
125 t.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
126 }
127
128 private class BlockInfo {
129 String japeURL;
130
131 int japeLine;
132
133 int startLine, endLine;
134
135 int startOffset, endOffset;
136
137 BlockInfo(String japeURL, int japeLine, int startLine, int endLine,
138 int startOffset, int endOffset) {
139
140 this.japeURL = japeURL;
141 this.japeLine = japeLine;
142 this.startLine = startLine;
143 this.endLine = endLine;
144 this.startOffset = startOffset;
145 this.endOffset = endOffset;
146 }
147
148 public boolean contains(int lineNumber) {
149 return (startLine <= lineNumber && lineNumber <= endLine);
150 }
151
152 public String getNumberedSource(String source) {
153 return Strings.addLineNumbers(getSource(source), japeLine);
154 }
155
156 public String getSource(String source, int line) {
157 String[] lines = getSource(source).split("\n");
158
159 return lines[line - japeLine];
160 }
161
162 public int getJapeLineNumber(int javaLineNumber) {
163 if(!contains(javaLineNumber)) return -1;
164
165 return japeLine + (javaLineNumber - startLine);
166 }
167
168 public StackTraceElement getStackTraceElement(int javaLineNumber) {
169 int japeLineNumber = getJapeLineNumber(javaLineNumber);
170
171 if(japeLineNumber == -1) return null;
172
173 return new StackTraceElement(phaseName, sectionName, japeURL,
174 japeLineNumber);
175 }
176
177 public String getSource(String source) {
178 return source.substring(startOffset, endOffset);
179 }
180 }
181 }
|