[Laszlo-checkins] r8546 - in openlaszlo/trunk/WEB-INF/lps: server/src/org/openlaszlo/compiler server/src/org/openlaszlo/sc templates
dda@openlaszlo.org
dda at openlaszlo.org
Thu Apr 3 17:22:32 PDT 2008
Author: dda
Date: 2008-04-03 17:22:24 -0700 (Thu, 03 Apr 2008)
New Revision: 8546
Modified:
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/NodeModel.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CompilerError.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Function.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9External.java
openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/TranslationUnit.java
openlaszlo/trunk/WEB-INF/lps/templates/app-console.xslt
Log:
Change 20080403-dda-n by dda at lester.local on 2008-04-03 13:30:55 EDT
in /Users/dda/laszlo/src/svn/openlaszlo/trunk-a
for http://svn.openlaszlo.org/openlaszlo/trunk
Summary: Fix error messages from compiler
New Features:
Bugs Fixed: LPP-5692
Technical Reviewer: ptw (pending)
QA Reviewer: hminsky (pending)
Doc Reviewer: (pending)
Documentation:
Release Notes:
Details:
There were several errors that prevented compilation error messages from being delivered
to the browser. Also running lzc gave an incorrect mapping of line numbers back to the
original.
SWF9External.java:
Fixed the pattern that matches the error message so that it is easier to extract
just the filename. This fixes problems of pathnames with dot (.) in them, and
remapped directory names due to symlinks.
In variable names and internal doc, renamed 'temp' directory to be 'work', so as
not to be confused with the app server's temp dir.
Cleaned up error messages. For the web, if possible to find the original line number, we show
that. For lzc, we always show both the SWF9 compiler line number and the original line number.
Remove the 'transitional' message that everyone was seeing in the browser, it no longer
applies in any case.
Count the number of lines in the preamble when we create a translation unit.
CompilerError.java:
Now extends CompilationError so it is treated uniformly with tag compiler errors.
Function.java
Separate the 'preface' of a function (includes pragmas) from the rest of the function,
so that the #line can be placed after the pragmas to avoid any line number skew.
TranslationUnit.java:
Track the offset where the text of the function starts so that the 'package {'
statement that appears at the beginning of the file doesn't throw off the line number count.
NodeModel.java, ClassModel.java:
separate pragmas from code when creating a 'Function' object.
app-console.xslt:
Translate newlines to <br /> in error messages, so that multiline error
messages are formatted nicely. Oddly, some string processing requires a bit
of work in XSLT.
Tests:
Inserted errors into .lzx files containing function bodies, and now see good error messages
with the right line numbers in the browser.
Regression: (smokecheck,weather) x (swf8,dhtml) + swf9/hello.lzx
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/ClassModel.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -152,8 +152,7 @@
// Apparently AS3 does not allow defaulting of
// primitive args
"$lzc$parent:LzNode? = null, $lzc$attrs:Object? = null, $lzc$children:Array? = null, $lzc$async:Boolean = false",
- body,
- null));
+ body));
// Build the class body
String classBody = "";
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/NodeModel.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/NodeModel.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/compiler/NodeModel.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -259,7 +259,7 @@
// value sent by sendEvent, so we have to accept it, but we
// ignore it
"$lzc$ignore=null",
- pragmas +
+ pragmas,
"this." + installer + "(" +
ScriptCompiler.quote(name) + "," +
body,
@@ -271,11 +271,12 @@
if (! when.equals(WHEN_ALWAYS)) {
return null;
}
- String body = "\n#pragma 'withThis'\n" +
- "return " + getCompiler().dependenciesForExpression(value);
+ String preface = "\n#pragma 'withThis'\n";
+ String body = "return " + getCompiler().dependenciesForExpression(value);
Function dependencies = new Function(
dependenciesname,
"",
+ preface,
body,
srcloc);
return dependencies;
@@ -1206,7 +1207,7 @@
args,
"\n#beginContent\n" +
"\n#pragma 'methodName=" + method + "'\n" +
- "\n#pragma 'withThis'\n" +
+ "\n#pragma 'withThis'\n",
body + "\n#endContent",
src_loc);
// Add hander as a method
@@ -1343,7 +1344,7 @@
args,
"\n#beginContent\n" +
"\n#pragma 'methodName=" + name + "'\n" +
- "\n#pragma 'withThis'\n" +
+ "\n#pragma 'withThis'\n",
body + "\n#endContent",
name_loc,
adjectives);
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CompilerError.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CompilerError.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CompilerError.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -3,8 +3,9 @@
package org.openlaszlo.sc;
import org.openlaszlo.sc.parser.SimpleNode;
+import org.openlaszlo.compiler.CompilationError;
-public class CompilerError extends RuntimeException {
+public class CompilerError extends CompilationError {
public SimpleNode node;
public CompilerError (String message) {
@@ -14,20 +15,27 @@
public CompilerError (String message, SimpleNode node) {
super(message);
- this.node = node;
+ attachNode(node);
}
public void attachNode(SimpleNode node) {
assert this.node == null;
this.node = node;
+ if (node != null) {
+ initPathname(node.filename);
+ initLineNumber(node.beginLine);
+ initColumnNumber(node.beginColumn);
+ }
}
public String toString() {
- return Compiler.getLocationString(node) + ": " + super.toString();
+ String loc = (node == null) ? "" :
+ (Compiler.getLocationString(node) + ": ");
+ return loc + super.toString();
}
}
/**
- * @copyright Copyright 2001-2007 Laszlo Systems, Inc. All Rights
+ * @copyright Copyright 2001-2008 Laszlo Systems, Inc. All Rights
* Reserved. Use is subject to license terms.
*/
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Function.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Function.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Function.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -10,6 +10,7 @@
public class Function {
public String name;
private final String args;
+ private final String preface;
private final String body;
private final String sourceLocation;
private final String adjectives;
@@ -23,16 +24,20 @@
}
public Function(String name, String args, String body) {
- this(name, args, body, null);
+ this(name, args, "", body, null);
}
- public Function(String name, String args, String body, String loc) {
- this(name, args, body, loc, null);
+ // When there is a source location, we ask that the body be broken
+ // up into a preface (any pragmas, etc. that the compiler must add)
+ // and the body - the original function body in the program.
+ public Function(String name, String args, String preface, String body, String loc) {
+ this(name, args, preface, body, loc, null);
}
- public Function(String name, String args, String body, String loc, String adjectives) {
+ public Function(String name, String args, String preface, String body, String loc, String adjectives) {
this.name = name;
this.args = args;
+ this.preface = preface;
this.body = body;
this.sourceLocation = loc;
this.adjectives = adjectives;
@@ -43,9 +48,13 @@
}
public String toString() {
+
return (adjectives != null?(adjectives + " "):"") +
"function " + name + "(" + args + ") {\n" +
- (sourceLocation != null?(sourceLocation + "\n"):"") +
+ preface +
+ // we do not inject a newline after sourceLocation, it was
+ // carefully positioned to be at the right column
+ (sourceLocation != null?sourceLocation:"") +
body +
"\n}";
}
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9External.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9External.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9External.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -26,7 +26,7 @@
*
* It is expected that a new SWF9External object
* be created for each chunk of compilation. Each
- * new SWF9External gets a new temporary directory
+ * new SWF9External gets a new temporary 'work' directory
* for compilation, and verifies classname uniqueness
* within that space.
*/
@@ -41,7 +41,22 @@
*/
public static final boolean USE_COMPILER_DEBUG_FLAG = true;
- private File tempdir = createCompilationTempDir();
+ /**
+ * A directory we create under the Java runtime's temp dir,
+ * that contains our compilation work directories, one for each compilation.
+ */
+ public static final String WORK_DIR_PARENT = "lzswf9";
+
+ /**
+ * The prefix for naming the work directories, which appear
+ * under the WORK_DIR_PARENT in the Java runtime's temp dir.
+ * For example, /tmp/lzswf9/lzgen...., although /tmp
+ * may be replaced by something else when running within
+ * tomcat or another application server.
+ */
+ public static final String WORK_DIR_PREFIX = "lzgen";
+
+ private File workdir = createCompilationWorkDir();
private Compiler.OptionMap options;
/**
@@ -95,11 +110,11 @@
}
/**
- * Create a temporary directory for compilation
+ * Create a temporary work directory for compilation
* and return a File for it.
* @throw CompilerError when directory creation fails
*/
- private File createCompilationTempDir()
+ private File createCompilationWorkDir()
{
// TODO: [2007-11-20 dda] Need some provisions for file
// cleanup on error, and on success too.
@@ -107,17 +122,17 @@
File f = null;
try {
String tmpdirstr = System.getProperty("java.io.tmpdir");
- String swf9tmpdirstr = tmpdirstr + File.separator + "lzswf9";
+ String swf9tmpdirstr = tmpdirstr + File.separator + WORK_DIR_PARENT;
(new File(swf9tmpdirstr)).mkdirs();
- f = File.createTempFile("lzgen", "", new File(swf9tmpdirstr));
+ f = File.createTempFile(WORK_DIR_PREFIX, "", new File(swf9tmpdirstr));
if (!f.delete())
- throw new CompilerError("getCompilationTempDir: temp file does not exist");
+ throw new CompilerError("getCompilationWorkDir: temp file does not exist");
if (!f.mkdir())
- throw new CompilerError("getCompilationTempDir: cannot make tempdir");
+ throw new CompilerError("getCompilationWorkDir: cannot make workdir");
}
catch (IOException ioe) {
- throw new CompilerError("getCompilationTempDir: cannot get temp directory: " + ioe);
+ throw new CompilerError("getCompilationWorkDir: cannot get temp directory: " + ioe);
}
return f;
}
@@ -131,7 +146,7 @@
if (new File(file).isAbsolute()) {
throw new IllegalArgumentException("workDirectoryName: file name must be relative");
}
- return tempdir.getPath() + File.separator + file;
+ return workdir.getPath() + File.separator + file;
}
@@ -230,6 +245,7 @@
this.linenum = linenum;
this.colnum = colnum;
this.error = error;
+ this.orig = orig;
}
public String toString() {
@@ -248,12 +264,9 @@
return error;
}
- // returns the complete the compiler error: e.g.
- // Error: variable 'x' undefined
- // result = x + 4;
- // ^
+ // returns the original untouched compiler error message
public String originalErrorString() {
- return orig + "\n" + code;
+ return orig;
}
// returns the complete the compiler error,
@@ -262,11 +275,11 @@
// other than just a newline. This is
// meant to be read in the browser.
// Error: variable 'x' undefined, in line: result = x + 4;
- // Compare this with originalErrorString().
public String cleanedErrorString() {
- String result = orig.trim();
- if (result.endsWith("."))
- result = result.substring(0, orig.length() - 1);
+ String result = error.trim();
+ while (result.endsWith("\n") || result.endsWith(".")) {
+ result = result.substring(0, result.length() - 1);
+ }
result += ", in line: " + cleanedCode;
return result;
}
@@ -322,7 +335,6 @@
*/
public class ExternalCompilerErrorCollector extends OutputCollector {
- private String relativeDir;
private String inputFilename;
private Pattern errPattern;
private List errors = new ArrayList();
@@ -332,30 +344,20 @@
// we don't expect this to be terribly big, can fit in memory
StringBuffer sb = new StringBuffer();
-
- public ExternalCompilerErrorCollector(InputStream is, List tunits, String relativeDir) {
+ public ExternalCompilerErrorCollector(InputStream is, List tunits) {
super(is);
- this.relativeDir = relativeDir;
this.inputFilename = inputFilename;
this.tunits = (TranslationUnit[])tunits.toArray(new TranslationUnit[0]);
// Expect errors to look like File.as(48): col: 1 Error: some message
- String pat = "([^.]+)\\.as\\(([0-9]+)\\): *col: *([0-9]*) *(.*)";
+ String pat = "([^\\/]+)\\.as\\(([0-9]+)\\): *col: *([0-9]*) *(.*)";
errPattern = Pattern.compile(pat);
//System.out.println("Using error pattern: " + pat);
}
public TranslationUnit locateTranslationUnit(String nm)
{
- // remove temporary directory from path
- int pos;
- if ((pos = nm.indexOf(relativeDir)) >= 0) {
- nm = nm.substring(pos + relativeDir.length());
- while (nm.length() > 0 && nm.charAt(0) == '/')
- nm = nm.substring(1);
- }
-
for (int i=0; i<tunits.length; i++) {
if (nm.equals(tunits[i].getName()))
return tunits[i];
@@ -457,7 +459,7 @@
try {
OutputStream os = proc.getOutputStream();
OutputCollector outcollect = new OutputCollector(proc.getInputStream());
- ExternalCompilerErrorCollector errcollect = new ExternalCompilerErrorCollector(proc.getErrorStream(), tunits, dir);
+ ExternalCompilerErrorCollector errcollect = new ExternalCompilerErrorCollector(proc.getErrorStream(), tunits);
os.close();
outcollect.start();
errcollect.start();
@@ -498,31 +500,29 @@
if (actualSrcFile == null)
actualSrcFile = "(" + tunit.getName() + ")";
}
- String actualSrcLine = actualSrcFile + ": " + err.getLineNumber();
- if (tunit == null ||
+
+ String actualSrcLine = "[" + actualSrcFile + ": " + err.getLineNumber() + "] ";
+
+ if (tunit == null ||
((srcLine = tunit.originalLineNumber(err.getLineNumber())) <= 0)) {
- srcLineStr = "[" + actualSrcLine + "]";
+ srcLineStr = "line unknown: ";
}
else {
- // For now, we also show the actual source file/line
- srcLineStr = String.valueOf(srcLine) +
- " [" + actualSrcLine + "]";
+ srcLineStr = "line " + String.valueOf(srcLine) + ": ";
}
- String errorSummary = srcLineStr +
- ": " + err.getErrorString() +
- "\n " + err.originalErrorString();
- System.err.println("Compiler error: at " + srcLineStr + ": " +
- err.getErrorString() + "\n " +
- err.originalErrorString());
+ System.err.println(actualSrcLine + srcLineStr + err.getErrorString());
+
+ // bigErrorString will be passed as an exception.
+ if (bigErrorString.length() > 0) {
+ bigErrorString += "\n";
+ }
bigErrorCount++;
if (bigErrorCount < MAX_ERRORS_SHOWN) {
- bigErrorString += srcLineStr + ": " +
- err.getErrorString() + "\n " +
- err.cleanedErrorString();
+ bigErrorString += srcLineStr + err.cleanedErrorString();
}
else if (bigErrorCount == 50) {
bigErrorString += ".... more than " + MAX_ERRORS_SHOWN +
- " errors, additional errors not shown.\n";
+ " errors, additional errors not shown.";
}
}
}
@@ -537,10 +537,6 @@
System.err.println("Done executing compiler");
if (!new File(outfileName).exists()) {
System.err.println("Intermediate file " + outfileName + ": does not exist");
- // TODO: [2008-1-17 dda] remove this transitional code in a couple months
- if (((String)cmd.get(0)).indexOf("mxmlc") >= 0) {
- throw new CompilerError("Errors from compiler - change compiler.swf9.lib.builder property in lps.properties to use compc rather than mxmlc?");
- }
if (bigErrorString.length() > 0) {
throw new CompilerError(bigErrorString);
}
@@ -606,14 +602,14 @@
cmd.add(getFlexPathname("bin/mxmlc" + exeSuffix));
}
- String outfilename = tempdir.getPath() + File.separator + outfilebase;
+ String outfilename = workdir.getPath() + File.separator + outfilebase;
boolean swf9Warnings = getLPSBoolean("compiler.swf9.warnings", true);
if (!swf9Warnings) {
cmd.add("-compiler.show-actionscript-warnings=false");
}
- cmd.add("-compiler.source-path+=" + tempdir.getPath());
+ cmd.add("-compiler.source-path+=" + workdir.getPath());
if (USE_COMPILER_DEBUG_FLAG) {
cmd.add("-debug=true");
}
@@ -638,7 +634,7 @@
// For a library, we list all the classes.
if (!buildSharedLibrary) {
if (tunit.isMainTranslationUnit()) {
- cmd.add(tempdir.getPath() + File.separator + tunit.getName()+".as");
+ cmd.add(workdir.getPath() + File.separator + tunit.getName()+".as");
}
}
else {
@@ -646,7 +642,7 @@
}
}
- execCompileCommand(cmd, tempdir.getPath(), tunits, outfilename);
+ execCompileCommand(cmd, workdir.getPath(), tunits, outfilename);
return getBytes(outfilename);
}
@@ -671,6 +667,18 @@
}
/**
+ * Return the number of newlines in the string.
+ */
+ public static int countLines(String str) {
+ int count = 0;
+ int pos = -1;
+ while ((pos = str.indexOf('\n', pos+1)) > 0) {
+ count++;
+ }
+ return count;
+ }
+
+ /**
* Write a file given by the translation unit, and using the
* given pre and post text.
* @throw CompilerError for any write errors, or class name conflicts
@@ -679,8 +687,9 @@
String name = tunit.getName();
String body = tunit.getContents();
checkFileNameForClassName(name);
- String infilename = tempdir.getPath() + File.separator + name + ".as";
+ String infilename = workdir.getPath() + File.separator + name + ".as";
tunit.setSourceFileName(infilename);
+ tunit.setLineOffset(countLines(pre));
if (options.getBoolean(Compiler.PROGRESS)) {
System.err.println("Creating: " + infilename);
@@ -716,7 +725,7 @@
}
/**
- * Emit a file relative to the temp directory,
+ * Emit a file relative to the work directory,
* using the TextEmitter as a source for the file text.
*/
public static void emitFile(String filename, TextEmitter tw) {
@@ -746,7 +755,7 @@
}
/**
- * emit a file relative to the temp directory with the given String text
+ * emit a file relative to the work directory with the given String text
*/
public static void emitFile(String filename, final String txt) {
emitFile(filename, new TextEmitter() {
@@ -758,7 +767,7 @@
}
/**
- * emit a file relative to the temp directory with the given node
+ * emit a file relative to the work directory with the given node
* (to be dumped) as the text.
*/
public static void emitFile(String filename, final SimpleNode node) {
Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/TranslationUnit.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/TranslationUnit.java 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/TranslationUnit.java 2008-04-04 00:22:24 UTC (rev 8546)
@@ -22,6 +22,7 @@
private StringBuffer text = new StringBuffer();
private SortedMap lnums = new TreeMap();
private int linenum = 1;
+ private int lineOffset = 0; // size of preamble, that otherwise messes with our line mapping
private String srcFilename; // name of associated source file, if applicable
private boolean isDefault = false; // stuff not within a class goes to default
private boolean isMain = false; // designated classes, like LFCApplication
@@ -57,6 +58,10 @@
this.srcFilename = srcname;
}
+ public void setLineOffset(int lineOffset) {
+ this.lineOffset = lineOffset;
+ }
+
/** Get text with any insertions resolved */
public String getContents() {
String result = text.toString();
@@ -141,6 +146,7 @@
public void dump() {
System.out.println("TranslationUnit[" + name + ", line " + linenum + "]");
System.out.println(" text=" + text);
+ System.out.println(" preamble line offset=" + lineOffset);
System.out.println(" linemap=");
for (Iterator iter=lnums.keySet().iterator(); iter.hasNext(); ) {
Object key = iter.next();
@@ -150,6 +156,7 @@
}
public int originalLineNumber(int num) {
+ num -= lineOffset;
SortedMap nextLineNumber = lnums.tailMap(new Integer(num));
if (nextLineNumber.size() == 0)
return -1;
Modified: openlaszlo/trunk/WEB-INF/lps/templates/app-console.xslt
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/templates/app-console.xslt 2008-04-03 23:15:56 UTC (rev 8545)
+++ openlaszlo/trunk/WEB-INF/lps/templates/app-console.xslt 2008-04-04 00:22:24 UTC (rev 8546)
@@ -318,6 +318,14 @@
</xsl:choose>
</xsl:template>
+ <xsl:template match="error">
+ <xsl:call-template name="str.subst">
+ <xsl:with-param name="str" select="." />
+ <xsl:with-param name="from" select="'
'" />
+ <xsl:with-param name="to"><br/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:template>
+
<xsl:template match="/errors">
<div style="border-top: 1px solid; border-bottom: 1px solid; background-color: #fcc; padding: 1pt; padding-left: 2pt">
The application could not be compiled due to the following errors:
@@ -343,6 +351,26 @@
<xsl:call-template name="footer"/>
</xsl:template>
+ <xsl:template name="str.subst">
+ <xsl:param name="str" />
+ <xsl:param name="from" />
+ <xsl:param name="to"><br /></xsl:param>
+ <xsl:choose>
+ <xsl:when test="contains($str, $from)">
+ <xsl:value-of select="substring-before($str, $from)" />
+ <xsl:copy-of select="$to" />
+ <xsl:call-template name="str.subst">
+ <xsl:with-param name="str" select="substring-after($str, $from)" />
+ <xsl:with-param name="from" select="$from" />
+ <xsl:with-param name="to" select="$to" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$str" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
</xsl:stylesheet>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
More information about the Laszlo-checkins
mailing list