/*******************************************************************************
*
* Copyright (C) 2008 Fujitsu Services Ltd.
*
* Author: Nick Battle
*
* This file is part of VDMJ.
*
* VDMJ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VDMJ 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package org.overture.interpreter.runtime;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.LexLocation;
import org.overture.ast.lex.LexNameList;
import org.overture.interpreter.VDMJ;
import org.overture.parser.config.Properties;
import org.overture.parser.lex.BacktrackInputReader;
/**
* A class to hold a source file for source debug output.
*/
public class SourceFile
{
public final File filename;
public final String charset;
public List<String> lines = new Vector<String>();
private final static String HTMLSTART = "<p class=MsoNormal style='text-autospace:none'><span style='font-size:10.0pt; font-family:\"Courier New\"; color:black'>";
private final static String HTMLEND = "</span></p>";
public SourceFile(File filename) throws IOException
{
this(filename, VDMJ.filecharset);
}
public SourceFile(File filename, String charset) throws IOException
{
this.filename = filename;
this.charset = charset;
BufferedReader br = new BufferedReader(new BacktrackInputReader(filename, charset));
String line = br.readLine();
while (line != null)
{
lines.add(line);
line = br.readLine();
}
br.close();
}
public String getLine(int n)
{
if (n < 1 || n > lines.size())
{
return "~";
}
return lines.get(n - 1);
}
public int getCount()
{
return lines.size();
}
public void printSource(PrintWriter out)
{
for (String line : lines)
{
out.println(line);
}
}
public void printCoverage(PrintWriter out)
{
List<Integer> hitlist = LexLocation.getHitList(filename);
List<Integer> srclist = LexLocation.getSourceList(filename);
int hitcount = 0;
int srccount = 0;
boolean supress = false;
out.println("Test coverage for " + filename + ":\n");
for (int lnum = 1; lnum <= lines.size(); lnum++)
{
String line = lines.get(lnum - 1);
// TODO remove this filtering it can never happen because of the new scanner
if (line.startsWith("\\begin{vdm_al}"))
{
supress = false;
continue;
} else if (line.startsWith("\\end{vdm_al}")
|| line.startsWith("\\section")
|| line.startsWith("\\subsection")
|| line.startsWith("\\document") || line.startsWith("%"))
{
supress = true;
continue;
}
if (srclist.contains(lnum))
{
srccount++;
if (hitlist.contains(lnum))
{
out.println("+ " + line);
hitcount++;
} else
{
out.println("- " + line);
}
} else
{
if (!supress)
{
out.println(" " + line);
}
}
}
out.println("\nCoverage = "
+ (srccount == 0 ? 0
: (float) (1000 * hitcount / srccount) / 10) + "%");
}
public void printWordCoverage(PrintWriter out)
{
Map<Integer, List<LexLocation>> hits = LexLocation.getMissLocations(filename);
out.println("<html>");
out.println("<head>");
out.println("<meta http-equiv=Content-Type content=\"text/html; charset="
+ VDMJ.filecharset + "\">");
out.println("<meta name=Generator content=\"Microsoft Word 11 (filtered)\">");
out.println("<title>" + filename.getName() + "</title>");
out.println("<style>");
out.println("<!--");
out.println("p.MsoNormal, li.MsoNormal, div.MsoNormal");
out.println("{margin:0in; margin-bottom:.0001pt; font-size:12.0pt; font-family:\"Times New Roman\";}");
out.println("h1");
out.println("{margin-top:12.0pt; margin-right:0in; margin-bottom:3.0pt; margin-left:0in; page-break-after:avoid; font-size:16.0pt; font-family:Arial;}");
out.println("@page Section1");
out.println("{size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in;}");
out.println("div.Section1");
out.println("{page:Section1;}");
out.println("-->");
out.println("</style>");
out.println("</head>");
out.println("<body lang=EN-GB>");
out.println("<div class=Section1>");
out.println("<h1 align=center style='text-align:center'>"
+ filename.getName() + "</h1>");
out.println(htmlLine());
out.println(htmlLine());
LexNameList spans = LexLocation.getSpanNames(filename);
for (int lnum = 1; lnum <= lines.size(); lnum++)
{
for (ILexNameToken name : spans)
{
if (name.getLocation().getStartLine() == lnum)
{
out.println("<a name=\"" + name.getName() + ":"
+ name.getLocation().getStartLine() + "\" />");
}
}
String line = lines.get(lnum - 1);
String spaced = detab(line, Properties.parser_tabstop);
List<LexLocation> list = hits.get(lnum);
out.println(markupHTML(spaced, list));
}
out.println(htmlLine());
out.println(htmlLine());
out.println(htmlLine());
out.println("<div align=center>");
out.println("<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=\"60%\" style='width:60.0%;border-collapse:collapse'>");
out.println(rowHTML(true, "Function or Operation", "Line", "Coverage", "Calls"));
long total = 0;
Collections.sort(spans);
for (ILexNameToken name : spans)
{
long calls = LexLocation.getSpanCalls(name);
total += calls;
out.println(rowHTML(false, "<a href=\"#" + name.getName() + ":"
+ name.getLocation().getStartLine() + "\">"
+ htmlQuote(name.toString()) + "</a>", name.getLocation().getStartLine()
+ "", Float.toString(LexLocation.getSpanPercent(name))
+ "%", Long.toString(calls)));
}
out.println(rowHTML(true, htmlQuote(filename.getName()), "", Float.toString(LexLocation.getHitPercent(filename))
+ "%", Long.toString(total)));
out.println("</table>");
out.println("</div>");
out.println("</div>");
out.println("</body>");
out.println("</html>");
}
private String htmlLine()
{
return "<p class=MsoNormal> </p>";
}
private String rowHTML(boolean emph, String name, String lineNumber,
String coverage, String calls)
{
StringBuilder sb = new StringBuilder();
String b1 = emph ? "<b>" : "";
String b2 = emph ? "</b>" : "";
String bg = emph ? "background:#D9D9D9;" : "";
sb.append("<tr>\n");
sb.append("<td width=\"50%\" valign=top style='width:50.0%;border:solid windowtext 1.0pt;"
+ bg + "padding:0in 0in 0in 0in'>\n");
sb.append("<p class=MsoNormal>" + b1 + name + b2 + "</p>\n");
sb.append("</td>\n");
sb.append("<td width=\"10%\" valign=top style='width:25.0%;border:solid windowtext 1.0pt;"
+ bg + "padding:0in 0in 0in 0in'>\n");
sb.append("<p class=MsoNormal align=right style='text-align:right'>"
+ b1 + lineNumber + b2 + "</p>\n");
sb.append("</td>\n");
sb.append("<td width=\"20%\" valign=top style='width:25.0%;border:solid windowtext 1.0pt;"
+ bg + "padding:0in 0in 0in 0in'>\n");
sb.append("<p class=MsoNormal align=right style='text-align:right'>"
+ b1 + coverage + b2 + "</p>\n");
sb.append("</td>\n");
sb.append("<td width=\"20%\" valign=top style='width:25.0%;border:solid windowtext 1.0pt;"
+ bg + "padding:0in 0in 0in 0in'>\n");
sb.append("<p class=MsoNormal align=right style='text-align:right'>"
+ b1 + calls + b2 + "</p>\n");
sb.append("</td>\n");
sb.append("</tr>\n");
return sb.toString();
}
private String markupHTML(String line, List<LexLocation> list)
{
if (line.isEmpty())
{
return htmlLine();
}
StringBuilder sb = new StringBuilder(HTMLSTART);
int p = 0;
if (list != null)
{
for (LexLocation m : list)
{
int start = m.startPos - 1;
int end = m.startLine == m.endLine ? m.endPos - 1
: line.length();
if (start >= p) // Backtracker produces duplicate tokens
{
sb.append(htmlQuote(line.substring(p, start)));
sb.append("<span style='color:red'>");
sb.append(htmlQuote(line.substring(start, end)));
sb.append("</span>");
p = end;
}
}
}
sb.append(htmlQuote(line.substring(p)));
sb.append(HTMLEND);
return sb.toString();
}
private String htmlQuote(String s)
{
return s.replaceAll("&", "&").replaceAll(" ", " ").replaceAll("<", "<").replaceAll(">", ">");
}
protected static String detab(String s, int tabstop)
{
StringBuilder sb = new StringBuilder();
int p = 0;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == '\t')
{
int n = tabstop - p % tabstop;
for (int x = 0; x < n; x++)
{
sb.append(' ');
}
p += n;
} else
{
sb.append(c);
p++;
}
}
return sb.toString();
}
public void writeCoverage(PrintWriter out)
{
for (LexLocation l : LexLocation.getSourceLocations(filename))
{
if (l.hits > 0)
{
out.println("+" + l.startLine + " " + l.startPos + "-"
+ l.endPos + "=" + l.hits);
}
}
}
}