package org.overture.interpreter.runtime; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; 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.config.Settings; import org.overture.parser.config.Properties; public class LatexSourceFile extends SourceFile { private static final String CURLY_BRACKET_VDM_AL = "{vdm_al}"; private static final String CURLY_BRACKET_VDM_SL = "{vdmsl}"; private static final String CURLY_BRACKET_VDM_PP = "{vdmpp}"; private static final String CURLY_BRACKET_VDM_RT = "{vdmrt}"; private static final String BREAKLINES_OPTION = "[breaklines=true]"; private static final String BEGIN = "\\begin"; private static final String END = "\\end"; public List<String> rawLines = new Vector<String>(); public final boolean hasVdm_al; // The argument to lstset is: escapeinside={(*@}{@*)} public final String LST_ESCAPE_BEGIN = "(*@"; public final String LST_ESCAPE_END = "@*)"; public LatexSourceFile(SourceFile source) throws IOException { this(source.filename, source.charset); } public LatexSourceFile(File filename, String charset) throws IOException { super(filename, charset); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), charset)); String line = br.readLine(); boolean vdm_al = false; while (line != null) { if (line.startsWith(BEGIN + CURLY_BRACKET_VDM_AL)) { vdm_al = true; } rawLines.add(line); line = br.readLine(); } hasVdm_al = vdm_al; br.close(); } public void printCoverage(PrintWriter out, boolean headers) { printCoverage(out, headers, false, true); } public void printCoverage(PrintWriter out, boolean headers, boolean modelOnly, boolean includeCoverageTable) { print(out, headers, modelOnly, includeCoverageTable, true); } public void print(PrintWriter out, boolean headers, boolean modelOnly, boolean includeCoverageTable, boolean markCoverage) { Map<Integer, List<LexLocation>> hits = null; if(includeCoverageTable || markCoverage) { hits = LexLocation.getMissLocations(filename); } if (headers) { out.println("\\documentclass[a4paper]{article}"); out.println("\\usepackage{longtable}"); // out.println("\\input{times}"); // out.println("\\input{graphicx}"); out.println("\\usepackage[color]{vdmlisting}"); out.println("\\usepackage{fullpage}"); out.println("\\usepackage{hyperref}"); out.println("\\begin{document}"); out.println("\\title{}"); out.println("\\author{}"); } if (!hasVdm_al) { out.println(BEGIN + getListingEnvironment()+BREAKLINES_OPTION); } boolean endDocFound = false; boolean inVdmAlModelTag = false; LexNameList spans = LexLocation.getSpanNames(filename); for (int lnum = 1; lnum <= rawLines.size(); lnum++) { for (ILexNameToken name : spans) { if (name.getLocation().getStartLine() == lnum) { out.println(LST_ESCAPE_BEGIN); out.println("\\label{" + latexLabel(name.getName()) + ":" + name.getLocation().getStartLine() + "}"); out.println(LST_ESCAPE_END); } } String line = rawLines.get(lnum - 1); if (line.contains("\\end{document}")) { endDocFound = true; break; } if (line.contains(BEGIN + CURLY_BRACKET_VDM_AL)) { inVdmAlModelTag = true; } if (hasVdm_al && modelOnly && !inVdmAlModelTag) { continue; } String spaced = detab(line, Properties.parser_tabstop); spaced = spaced.replace(BEGIN + CURLY_BRACKET_VDM_AL, BEGIN + getListingEnvironment()+BREAKLINES_OPTION).replace(END + CURLY_BRACKET_VDM_AL, END + getListingEnvironment()); if (markCoverage) { List<LexLocation> list = hits.get(lnum); out.println(markup(spaced, list)); } else { out.println(spaced); } if (line.contains(END + getListingEnvironment())) { inVdmAlModelTag = false; } } if (!hasVdm_al) { out.println(END + getListingEnvironment()); } if (includeCoverageTable) { out.println("\\bigskip"); out.println(createCoverageTable()); } if (headers || endDocFound) { out.println("\\end{document}"); } } private String getListingEnvironment() { switch (Settings.dialect) { case VDM_PP: return CURLY_BRACKET_VDM_PP; case VDM_RT: return CURLY_BRACKET_VDM_RT; case VDM_SL: return CURLY_BRACKET_VDM_SL; case CML: default: return CURLY_BRACKET_VDM_AL; } } private String createCoverageTable() { StringBuilder sb = new StringBuilder(); sb.append("\\begin{longtable}{|l|r|r|r|}" + "\n"); sb.append("\\hline" + "\n"); sb.append("Function or operation & Line & Coverage & Calls \\\\" + "\n"); sb.append("\\hline" + "\n"); sb.append("\\hline" + "\n"); long total = 0; LexNameList spans = LexLocation.getSpanNames(filename); Collections.sort(spans); for (ILexNameToken name : spans) { long calls = LexLocation.getSpanCalls(name); total += calls; sb.append("\\hyperref[" + latexLabel(name.getName()) + ":" + name.getLocation().getStartLine() + "]{" + latexQuote(name.toString()) + "} & " + name.getLocation().getStartLine() + "&" + LexLocation.getSpanPercent(name) + "\\% & " + calls + " \\\\" + "\n"); sb.append("\\hline" + "\n"); } sb.append("\\hline" + "\n"); sb.append(latexQuote(filename.getName()) + " & & " + LexLocation.getHitPercent(filename) + "\\% & " + total + " \\\\" + "\n"); sb.append("\\hline" + "\n"); sb.append("\\end{longtable}" + "\n"); return sb.toString(); } private String markup(String line, List<LexLocation> list) { if (list == null) { return line; } else { StringBuilder sb = new StringBuilder(); int p = 0; 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(line.substring(p, start)); sb.append(LST_ESCAPE_BEGIN + "\\vdmnotcovered{"); sb.append(latexQuote(line.substring(start, end))); sb.append("}" + LST_ESCAPE_END); // \u00A3"); p = end; } } sb.append(line.substring(p)); return sb.toString(); } } private String latexQuote(String s) { // Latex specials: \# \$ \% \^{} \& \_ \{ \} \~{} \\ return s.replace("\\", "\\textbackslash ").replace("#", "\\#").replace("$", "\\$").replace("%", "\\%").replace("&", "\\&").replace("_", "\\_").replace("{", "\\{").replace("}", "\\}").replace("~", "\\~").replaceAll("\\^{1}", "\\\\^{}"); } private String latexLabel(String s) { // Latex specials: \# \$ \% \^{} \& \_ \{ \} \~{} \\ return s.replace("\\", ":").replace("#", ":").replace("$", ":").replace("%", ":").replace("&", ":").replace("_", ":").replace("{", ":").replace("}", ":").replace("~", ":").replaceAll("\\^{1}", ":"); } }