[Laszlo-checkins] r9223 - in openlaszlo/trunk/WEB-INF/lps: lfc server/src/org/openlaszlo/sc

dda@openlaszlo.org dda at openlaszlo.org
Mon May 19 12:19:51 PDT 2008


Author: dda
Date: 2008-05-19 12:19:39 -0700 (Mon, 19 May 2008)
New Revision: 9223

Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/build.xml
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CommonGenerator.java
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9ParseTreePrinter.java
   openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ScriptCompiler.java
Log:
Change 20080518-dda-6 by dda at lester.local on 2008-05-18 16:02:23 EDT
    in /Users/dda/laszlo/src/svn/openlaszlo/trunk-c
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Script compiler line number rework

New Features:

Bugs Fixed: LPP-5784

Technical Reviewer: ptw (pending)
QA Reviewer: promanik (pending)
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:
    General:
       A fair amount of rework of the line numbers.  We needed an integrated
       approach so that internally at least, /* file: name#xx.yy */ wasn't
       treated separately from /* file: #xx */.  More line information needed
       to be preserved to capture all the various line transitions.  These
       had various ripple effects, one being that versions of the LFC
       (compiled with nameFunctions) needed to have trackLines turned off,
       otherwise heap space blew up.  This may be fixable in the future if it
       is important.  LFC still has /* -*- file: .... */ comments for the
       top of functions.
       
       Also observed during testing is the necessity of not breaking output
       lines to insert /* -*- file: .... */ comments.  This breaks lzunit
       test/lztest/lztest-node-options.js in a strange manner:
       
            [exec] js: "test/lztest/lztest-node-options.js", line 108: uncaught JavaScript runtime exception: TypeError: org.mozilla.javascript.Undefined at 992bae is not a function, it is org.mozilla.javascript.Undefined.
    
       A working lztest-node-options.js differed from the broken one only in
       the comments produced.  This remains a mystery, but without much
       loss of line number accuracy, we now should not break lines.
    
    lfc/build.xml
       Turn off -tracklines when building the LFC, it can overflow heap space
       due to enormous strings generated internally.
    
    ScriptCompiler.java, Compiler.java:
       Eliminate needless call to Compiler.setProperties(),
       and eliminate that method.  Compiler.defaultOptions() is
       now only called once.
    
    Compiler.java:
       Support disableTrackLines option.
    
    Compiler.java, CommonGenerator.java:
       Fragments generated with fake filenames are now issued with [filename]
    
    SWF9ParseTreePrinter.java:
       More thorough checking of class 'type'
    
    ParseTreePrinter.java
       - Added extra debugging output for line numbers (DEBUG_LINE_NUMBER)
    
       - Integrate file/line numbering to a common approach.
         There are still two annotations, but they both contain file/line
         numbers and they are processed the same.  One is marked as a
         'forced' line number so that a line number will sure to be
         emitted at the beginning of a function.
    
       - allow more internal line annotations to be created -
         don't automatically elim an annotation just because it is
         followed by another annotation.  The intelligence about
         what to finally produce happens at the end.
    
       - added capability to extract a single annotation.
    
       - encapsulate current and last line number info in
         a LineNumberState struct to make comparison and updating
         easier and clearer.
    
       - when outputting the line numbers, fine tune the conditions for
         when we need a new source location.  Some of the factors in
         the decision are:
           -- is it the same as can be predicted?
           -- does the current/previous filename have a name?
              and is the name internal (used for compiling a fragment)?
              and the line number >0?
           -- are we at the beginning of a line (the preferred spot,
              but there are exceptions)?
           -- is this the beginning of a function?
           -- is trackLines on?
         this is all managed in shouldShowSourceLocation().
    
       - there are now three variants of line number (source locations
         using the nexb terminology) emitted:
             /* -*- file: -*- */
                     There is no file attached to the following code
                     Don't expect to see line numbers updated.
             /* -*- file: FILENAME#NN.YY -*- */
                     The filename has changed.  The following output line
                     relates to line NN (and column YY) of FILENAME as the
                     input file.  Subsequent output lines numbers can be
                     determined by simple incrementing.
             /* -*- file: #NN */-*- */
                     The following output line relates to line NN of the
                     previously mentioned FILENAME as the input file.
                     Subsequent output lines numbers can be
                     determined by simple incrementing.
          At the beginning of output, there is no file attached
          until the first source location is seen.  That is there is
          an implicit  /* -*- file: -*- */ at the beginning of output.
    
Tests:
   Functionality:
       Test cases from nexb #449 and #443 work by examining output JS.
       In particular output not relating to particular input source lines
       are indicated with /* -*- file: -*- */
          https://nexb.laszlosystems.com/trac/main/ticket/443
          https://nexb.laszlosystems.com/trac/main/ticket/449
      Compiled for example:
         lzc -DnameFunctions --runtime=dhtml -S nexb443.lzx

   Regression:
      ant lzunit
      swf9 hello
      (smokecheck,weather,lzunit) x (swf8,dhtml)



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/build.xml
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/build.xml	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/build.xml	2008-05-19 19:19:39 UTC (rev 9223)
@@ -172,7 +172,7 @@
           // warnings, the options can be changed to simply --debug
           dobuild(dest,
                   "dhtml",
-                  "--option nameFunctions --option warnGlobalAssignments '-D$debug=true'");
+                  "--option nameFunctions --option disableTrackLines --option warnGlobalAssignments '-D$debug=true'");
         }
         if (buildDebugSimple) {
           var dest = LFCdir + "LFCdhtml-debug-simple.js";
@@ -181,7 +181,7 @@
             // warnings, the options can be changed to simply --debug
             dobuild(dest,
                     "dhtml",
-                    "--option debugSimple --option nameFunctions --option warnGlobalAssignments '-D$debug=true'");
+                    "--option debugSimple --option nameFunctions --option disableTrackLines --option warnGlobalAssignments '-D$debug=true'");
           }
         }
         var dest = LFCdir + "LFCdhtml-backtrace.js";
@@ -190,7 +190,7 @@
           // warnings, the options can be changed to simply -g3
           dobuild(dest,
                   "dhtml",
-                  "--option debugBacktrace --option nameFunctions --option warnGlobalAssignments '-D$debug=true'");
+                  "--option debugBacktrace --option nameFunctions --option disableTrackLines --option warnGlobalAssignments '-D$debug=true'");
         }
         if (buildDebugSimple) {
           var dest = LFCdir + "LFCdhtml-backtrace-simple.js";
@@ -199,7 +199,7 @@
             // warnings, the options can be changed to simply -g3
             dobuild(dest,
                     "dhtml",
-                    "--option debugSimple --option debugBacktrace --option nameFunctions --option warnGlobalAssignments '-D$debug=true'");
+                    "--option debugSimple --option debugBacktrace --option nameFunctions --option disableTrackLines --option warnGlobalAssignments '-D$debug=true'");
           }
         }
       }

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CommonGenerator.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CommonGenerator.java	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/CommonGenerator.java	2008-05-19 19:19:39 UTC (rev 9223)
@@ -168,7 +168,7 @@
     code =
       "{" +
       "\n#pragma 'warnUndefinedReferences=false'\n" +
-      "\n#file JavascriptGenerator.parseFragment\n#line 0\n" +
+      "\n#file [CommonGenerator.parseFragment]\n#line 0\n" +
       code +
       "}";
     // Extract the statement list from the program

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/Compiler.java	2008-05-19 19:19:39 UTC (rev 9223)
@@ -263,11 +263,8 @@
   // Set internal flags that depend on external flags
   public void defaultOptions() {
 
-    // TODO: [2008-04-21 dda] defaultOptions() can be called multiple
-    // times: from Compiler() default constructor and also from
-    // Compiler.setProperties().  This makes the maintenence of this
-    // code needlessly tricky.  Should be reworked to only call this
-    // once.
+    // TODO: [2008-05-18 dda] It may be possible to clean this up
+    // a little now that we know this is only called once.
 
     if (options.getBoolean(DEBUG)) {
       options.put(WARN_UNDEFINED_REFERENCES, Boolean.TRUE);
@@ -301,39 +298,17 @@
     if (! options.containsKey(PROFILE)) {
       options.putBoolean(PROFILE, false);
     }
+    if (!options.containsKey(DISABLE_TRACK_LINES) &&
+        options.getBoolean(NAME_FUNCTIONS)) {
+      options.putBoolean(TRACK_LINES, true);
+    }
     if (options.getBoolean(PROFILE)) {
       options.putBoolean(NAME_FUNCTIONS, true);
     }
-    if (! options.containsKey(TRACK_LINES) && options.getBoolean(NAME_FUNCTIONS)) {
-      options.putBoolean(TRACK_LINES, true);
-    }
     options.putBoolean(GENERATE_FUNCTION_2, true);
     options.putBoolean(GENERATE_FUNCTION_2_FOR_LZX, true);
   }
 
-  public void setProperties(Map properties) {
-    // Canonicalize String-valued properties.  This is pretty bogus
-    // (dispatching on the value to decide if the property is a
-    // boolean-valued property, but it is the way the compiler always
-    // worked.
-    for (Iterator i = properties.keySet().iterator(); i.hasNext(); ) {
-      Object key = i.next();
-      Object value = properties.get(key);
-      if (value instanceof String) {
-        String v = (String)value;
-        if ("true".equalsIgnoreCase(v) || "false".equalsIgnoreCase(v)) {
-          options.putBoolean(key, v);
-          continue;
-        }
-      }
-      options.put(key, value);
-    }
-    defaultOptions();
-    if (options.getBoolean(PRINT_COMPILER_OPTIONS)) {
-      System.err.println("set compiler options" +  options.toString());
-    }
-  }
-
   public byte[] compile(String source) {
     try {
       Profiler profiler = new Profiler();
@@ -478,6 +453,7 @@
   public static String DUMP_AST_INPUT = "dumpASTInput";
   public static String DUMP_AST_OUTPUT = "dumpASTOutput";
   public static String DISABLE_CONSTANT_POOL = "disableConstantPool";
+  public static String DISABLE_TRACK_LINES = "disableTrackLines";
   public static String ELIMINATE_DEAD_EXPRESSIONS = "eliminateDeadExpressions";
   public static String FLASH_COMPILER_COMPATABILITY = "flashCompilerCompatability";
   public static String GENERATE_FUNCTION_2 = "generateFunction2";
@@ -786,7 +762,7 @@
     public SimpleNode substitute(String str, Map keys) {
       // Since the parser can't parse an Expression, turn the source
       // into a Program, and extract the Expression from the parse tree.
-      SimpleNode node = parse("x = \n#file Compiler.substitute\n#line 0\n" + str).get(0).get(0).get(2);
+      SimpleNode node = parse("x = \n#file [Compiler.substitute]\n#line 0\n" + str).get(0).get(0).get(2);
       return visit(node, keys);
     }
 
@@ -798,7 +774,7 @@
     }
 
     public SimpleNode substituteStmt(String str, Map keys) {
-      SimpleNode node = parse("#file Compiler.substitute\n#line 0\n" + str).get(0);
+      SimpleNode node = parse("#file [Compiler.substitute]\n#line 0\n" + str).get(0);
       return visit(node, keys);
     }
 

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ParseTreePrinter.java	2008-05-19 19:19:39 UTC (rev 9223)
@@ -45,6 +45,7 @@
 
   // For debugging
   public static final boolean DEBUG_NODE_OUTPUT = false;
+  public static final boolean DEBUG_LINE_NUMBER = false;
 
   boolean compress;
   boolean trackLines;
@@ -749,7 +750,7 @@
     String txt = "";
     // Add location information if not compressing
     if ((!this.compress) && (node.filename != null) && (node.beginLine != 0)) {
-      txt = annotateFileLineNumber(Compiler.getLocationString(node));
+      txt = annotateFileLineNumber(Compiler.getLocationString(node), true);
     }
     txt += "function" + (useName ? (" " + name) : "") + OPENPAREN + args + CLOSEPAREN;
     if (!inmixin) {
@@ -888,26 +889,91 @@
   public static final char ANNOTATE_OP_CLASSNAME = 'C';
   public static final char ANNOTATE_OP_CLASSEND = 'c';
   public static final char ANNOTATE_OP_INSERTSTREAM = 'i';
-  public static final char ANNOTATE_OP_LINENUM = 'L';
-  public static final char ANNOTATE_OP_FILE_LINENUM = 'F';
+  public static final char ANNOTATE_OP_FILE_LINENUM = 'f';
+  public static final char ANNOTATE_OP_FILE_LINENUM_FORCE = 'F';
   public static final char ANNOTATE_OP_NODENAME = 'N';
   public static final char ANNOTATE_OP_NODEEND = 'n';
   public static final char ANNOTATE_OP_TEXT = 'T';
   
+  public static class DecodedAnnotation {
+    char op;
+    String operand;
+  }
+
   /**
+   * Return the first annotation only.
+   */
+  public DecodedAnnotation firstAnnotation(String str) {
+    final DecodedAnnotation ann = new DecodedAnnotation();
+    AnnotationProcessor ap = new AnnotationProcessor() {
+        public String notify(char op, String operand) {
+          switch (op) {
+          case ANNOTATE_OP_TEXT:
+            break;
+          default:
+            ann.op = op;
+            ann.operand = operand;
+            break;
+          }
+          return "";
+        }
+      };
+    // Only look at the first annotation
+    ap.setLimit(1);
+    ap.process(str);
+    if (ann.operand == null)
+      return null;
+    else
+      return ann;
+  }
+
+  /**
+   * Return true if the node gives new useful line information
+   * beyond what is in the annotation.
+   */
+  public boolean fileLineNumberNeeded(DecodedAnnotation ann, SimpleNode node) {
+    if (ann == null ||
+        (ann.op != ANNOTATE_OP_FILE_LINENUM &&
+         ann.op != ANNOTATE_OP_FILE_LINENUM_FORCE)) {
+      return false;
+    }
+    int nodeLinenum = node.getLineNumber();
+    String nodeFilename = node.getFilename();
+    int annLinenum = extractLineNumber(ann.operand);
+    String annFilename = extractFileName(ann.operand);
+
+    if (nodeFilename == null || nodeFilename.length() == 0) {
+      nodeFilename = "";
+      nodeLinenum = 0;
+    }
+    if (annFilename == null || annFilename.length() == 0) {
+      annFilename = "";
+      annLinenum = 0;
+    }
+    return (!nodeFilename.startsWith("[") &&
+            (!annFilename.equals(nodeFilename) || annLinenum != nodeLinenum));
+  }
+
+  /**
    * Prefix line number annotation to a string.
    */
   public String lnum(SimpleNode node, String str) {
-    int linenum = node.getLineNumber();
-    if (linenum < 0)
+    if (!trackLines)
       return str;
-    if (str.length() > 0 && str.charAt(0) == ANNOTATE_MARKER)
-      return str;
 
-    StringBuffer sb = new StringBuffer();
-    sb.append(makeAnnotation(ANNOTATE_OP_LINENUM, String.valueOf(linenum)));
-    sb.append(str);
-    String result = sb.toString();
+    // If we are not already at an annotation at the same file/line number,
+    // then produce one.
+    String result = "";
+    if (str.length() <= 1 || str.charAt(0) != ANNOTATE_MARKER ||
+        fileLineNumberNeeded(firstAnnotation(str), node)) {
+      // TODO: [2008-05-18 dda] If there is already a line annotation
+      // here, consider replacing it, rather than adding to it so we
+      // don't balloon the size of the annotated string.  But for now,
+      // we wish to push the real line number intelligence to the end
+      // of processing.
+      result = annotateFileLineNumber(Compiler.getLocationString(node), false);
+    }
+    result += str;
 
     if (DEBUG_NODE_OUTPUT)
       result = annotateNode(node, result);
@@ -951,8 +1017,18 @@
     return sb.toString();
   }
 
-  public String annotateFileLineNumber(String encodedFileLineNumber) {
-    return makeAnnotation(ANNOTATE_OP_FILE_LINENUM, encodedFileLineNumber);
+  // TODO: [2008-05-18 dda] line number annotations contain the full
+  // text of the file name plus a line number.  This can be wasteful
+  // in string space (it is not currently possible to compile the full
+  // LFC with trackLines on).  A better approach would be to use a
+  // number in place of the file name, the number being an index in a
+  // dictionary of names, kept in the instance of the
+  // ParseTreePrinter.
+  //
+  public String annotateFileLineNumber(String fileLineNumber, boolean force
+) {
+    char op = force ? ANNOTATE_OP_FILE_LINENUM_FORCE : ANNOTATE_OP_FILE_LINENUM;
+    return makeAnnotation(op, fileLineNumber);
   }
 
   /**
@@ -964,7 +1040,13 @@
   }
   
   public abstract static class AnnotationProcessor {
+    int limit = -1;
     public abstract String notify(char op, String operand);
+    /** Limit the number of annotations to process, -1 means no limit */
+    public void setLimit(int limit) {
+      assert(limit != 0);
+      this.limit = limit;
+    }
     public String process(String annotated) {
       int alen = annotated.length();
       StringBuffer sb = new StringBuffer();
@@ -985,6 +1067,11 @@
           throw new IllegalArgumentException("bad line number annotations:");
         }
         sb.append(notify(op, annotated.substring(startann+2, endann)));
+        if (limit >= 0) {
+          if (--limit <= 0) {
+            return "";
+          }
+        }
         startann = annotated.indexOf(ANNOTATE_MARKER, endann+1);
       }
       String outstr = annotated.substring(endann+1);
@@ -1000,19 +1087,13 @@
           switch (op) {
           case ANNOTATE_OP_TEXT:
             return operand;
-          case ANNOTATE_OP_FILE_LINENUM:
-            /* File/linenums annotations are added only when
-             * nameFunctions is on.  Here we pass them through
-             * unconditionally.
-             */
-            return "\n/* -*- file: " + operand + " -*- */\n";
           }
           return "";
         }
       };
     return ap.process(annotated);
   }
-  
+
   public String printableAnnotations(String annotated) {
     final LinkedList nodestack = new LinkedList();
     AnnotationProcessor ap = new AnnotationProcessor() {
@@ -1020,10 +1101,10 @@
           switch (op) {
           case ANNOTATE_OP_TEXT:
             return operand;
-          case ANNOTATE_OP_LINENUM:
-            return "#line " + operand + ": ";
           case ANNOTATE_OP_FILE_LINENUM:
             return "#fileline " + operand + ": ";
+          case ANNOTATE_OP_FILE_LINENUM_FORCE:
+            return "#filelineforce " + operand + ": ";
           case ANNOTATE_OP_CLASSNAME:
             return "#class " + operand + ": ";
           case ANNOTATE_OP_CLASSEND:
@@ -1049,9 +1130,48 @@
   public int extractLineNumber(String str) {
     int linenumPos = str.indexOf('#');
     int linenumEnd = str.indexOf('.', linenumPos+1);
+    if (linenumPos < 0) {
+      return 0;
+    }
+    if (linenumEnd < 0) {
+      linenumEnd = str.length();
+    }
     return Integer.parseInt(str.substring(linenumPos+1, linenumEnd));
   }
 
+  public String extractFileName(String str) {
+    int linenumPos = str.indexOf('#');
+    if (linenumPos >= 0) {
+      return str.substring(0, str.indexOf('#'));
+    }
+    else {
+      return str;
+    }
+  }
+
+  public static class LineNumberState {
+    String filename = "";
+    boolean hasfile = false;
+    int linenum = Integer.MIN_VALUE;
+    int linediff = Integer.MIN_VALUE;
+  }
+
+  public boolean isActualFile(String str) {
+    // TODO: handle Compiler. etc.
+    return (!str.equals("") && !str.startsWith("["));
+  }
+
+  public LineNumberState getLineNumberState(TranslationUnit tu, String operand) {
+    LineNumberState lnstate = new LineNumberState();
+    lnstate.filename = extractFileName(operand);
+    lnstate.hasfile = isActualFile(lnstate.filename);
+    if (lnstate.hasfile) {
+      lnstate.linenum = extractLineNumber(operand);
+      lnstate.linediff = tu.getTextLineNumber() - lnstate.linenum;
+    }
+    return lnstate;
+  }
+
   public List makeTranslationUnits(String annotated) {
     final ArrayList tunits = new ArrayList();
     final TranslationUnit defaulttu = new TranslationUnit(true);
@@ -1064,25 +1184,96 @@
     AnnotationProcessor ap = new AnnotationProcessor() {
         TranslationUnit curtu = defaulttu;
         boolean atBol = true;
-        int linenumDiff = 0;
-        int newdiff;
-        int linenum;
+        LineNumberState curLstate = new LineNumberState();
 
+        public boolean shouldShowSourceLocation(LineNumberState os,
+                                                LineNumberState ns,
+                                                char op,
+                                                boolean atBol) {
+          boolean fileSame = os.filename.equals(ns.filename);
+          boolean lineSame = (os.linediff == ns.linediff);
+
+          boolean showSrcloc = false;
+
+          // Show source location if we are tracing linenums and the
+          // file is the same and we're either at the beginning of a
+          // line or we have a real filename or we're at the beginning
+          // of line.  There are many compiler substitutions within
+          // statements, and we don't want to break up output lines
+          // with pointless srclocs.
+
+          if (!fileSame && trackLines) {
+
+            // We need to emit at the beginning of the line,
+            // even if the file has changed.  If we break up lines,
+            // we may alter the meaning of the javascript -
+            // 'return foo' can become 
+            //    return
+            //    foo
+            // (two separate statements).
+
+            if (atBol && (ns.hasfile || os.hasfile)) {
+              showSrcloc = true;
+            }
+          }
+          // Show source location if we are 'forced' to and have a name
+          // No check for atBol here, a LINENUM_FORCE should only be used
+          // in cases where it is safe to break lines.
+
+          else if (op == ANNOTATE_OP_FILE_LINENUM_FORCE &&
+                   ns.filename.length() > 0) {
+            showSrcloc = true;
+          }
+          // Otherwise, at the beginning of a line, show it if it has changed.
+          else if (atBol && trackLines && ns.linenum > 0 &&
+                   (!lineSame || !fileSame)) {
+            showSrcloc = true;
+          }
+
+          // If debugging, indicate the reasons we are or are not showing loc
+          if (DEBUG_LINE_NUMBER && trackLines) {
+
+            String shorthand = showSrcloc ? "L: " : "!L: ";
+            if (!ns.hasfile) {
+              shorthand += "!file ";
+            }
+            if (!fileSame) {
+              shorthand += "!fsame ";
+            }
+            if (!lineSame) {
+              shorthand += "!lsame ";
+            }
+            if (op == ANNOTATE_OP_FILE_LINENUM_FORCE) {
+              shorthand += "force ";
+            }
+            curtu.addText("/* " + shorthand + "*/");
+          }
+
+          return showSrcloc;
+        }
+
         public String notify(char op, String operand) {
           switch (op) {
           case ANNOTATE_OP_TEXT:
-            curtu.addText(operand);
-            if (trackLines) {
-              if (operand.endsWith("\n")) {
-                atBol = true;
+            if (DEBUG_LINE_NUMBER) {
+              int nl = operand.indexOf('\n');
+              if (nl >= 0) {
+                int curline = curtu.getTextLineNumber();
+                operand = operand.substring(0, nl) +
+                  "   /* #" + curline + " */" +
+                  operand.substring(nl);
               }
-              else if (operand.length() > 0) {
-                atBol = false;
-              }
             }
+            curtu.addText(operand);
+            if (operand.endsWith("\n")) {
+              atBol = true;
+            }
+            else if (operand.length() > 0) {
+              atBol = false;
+            }
             return "";
 
-          /* We always emit the FILE_LINENUM annotations (they appear
+          /* We always emit the FILE_LINENUM_FORCE annotations (they appear
            * at beginning of functions) but plain old line number
            * annotations are emitted only if the line information
            * cannot be determined from the previous 'file: ' marker
@@ -1092,23 +1283,28 @@
            * changes, we know an observer of the output would be off
            * and it's time to output a line number marker.
            */
-          case ANNOTATE_OP_LINENUM:
-            linenum = Integer.parseInt(operand);
-            if (trackLines && atBol && linenum != 0) {
-              newdiff = curtu.getTextLineNumber() - linenum;
-              if (newdiff != linenumDiff) {
-                curtu.addText("/* -*- file: #" + linenum + " -*- */\n");
-                linenumDiff = curtu.getTextLineNumber() - linenum;
+          case ANNOTATE_OP_FILE_LINENUM_FORCE:
+          case ANNOTATE_OP_FILE_LINENUM:
+            LineNumberState newLstate = getLineNumberState(curtu, operand);
+
+            if (shouldShowSourceLocation(curLstate, newLstate, op, atBol)) {
+              String srcloc = atBol ? "" : "\n";
+              if (op == ANNOTATE_OP_FILE_LINENUM_FORCE) {
+                srcloc += "/* -*- file: " + operand + " -*- */\n";
+              } else if (newLstate.filename.length() == 0) {
+                srcloc += "/* -*- file: -*- */\n";
+              } else if (curLstate.filename.equals(newLstate.filename)) {
+                srcloc += "/* -*- file: #" + newLstate.linenum + " -*- */\n";
               }
+              else {
+                srcloc += "/* -*- file: " + operand + " -*- */\n";
+              }
+              curtu.addText(srcloc);
+              curtu.setInputLineNumber(curLstate.linenum);
+              newLstate.linediff++; // compensate for line just added
+              curLstate = newLstate;
             }
-            curtu.setInputLineNumber(linenum);
             return "";
-          case ANNOTATE_OP_FILE_LINENUM:
-            linenum = extractLineNumber(operand);
-            curtu.addText("\n/* -*- file: " + operand + " -*- */\n");
-            linenumDiff = curtu.getTextLineNumber() - linenum;
-            curtu.setInputLineNumber(linenum);
-            return "";
           case ANNOTATE_OP_CLASSNAME:
             curtu = new TranslationUnit();
             curtu.setName(operand);

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9ParseTreePrinter.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9ParseTreePrinter.java	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/SWF9ParseTreePrinter.java	2008-05-19 19:19:39 UTC (rev 9223)
@@ -222,12 +222,16 @@
 
     // Everything inserted by #passthrough (toplevel:true) goes here.
     sb.append(annotateInsertStream(TOP_LEVEL_STREAM));
-    if ("class".equals(unannotate(children[0]))) {
+    String classtype = unannotate(children[0]);
+    if ("class".equals(classtype)) {
       sb.append("class");
     }
-    else {
+    else if ("interface".equals(classtype) || "trait".equals(classtype)) {
       sb.append("interface");
     }
+    else {
+      throw new CompilerError("Internal error: bad classtype: " + classtype);
+    }
     sb.append(SPACE + classnm + SPACE);
     if (unannotate(children[2]).length() > 0)
       sb.append("extends" + SPACE + children[2] + SPACE);

Modified: openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ScriptCompiler.java
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ScriptCompiler.java	2008-05-19 11:48:53 UTC (rev 9222)
+++ openlaszlo/trunk/WEB-INF/lps/server/src/org/openlaszlo/sc/ScriptCompiler.java	2008-05-19 19:19:39 UTC (rev 9223)
@@ -108,8 +108,7 @@
     private static byte[] _compileToByteArray(String script,
                                               Properties properties) {
         org.openlaszlo.sc.Compiler compiler =
-            new org.openlaszlo.sc.Compiler();
-        compiler.setProperties(properties);
+            new org.openlaszlo.sc.Compiler(properties);
         try {
             return compiler.compile(script);
         } catch (org.openlaszlo.sc.parser.TokenMgrError e) {



More information about the Laszlo-checkins mailing list