[seam-commits] Seam SVN: r8470 - trunk.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Jul 16 08:27:55 EDT 2008


Author: christian.bauer at jboss.com
Date: 2008-07-16 08:27:54 -0400 (Wed, 16 Jul 2008)
New Revision: 8470

Modified:
   trunk/seam-text.g
Log:
Improved SeamTextParser error handling

Modified: trunk/seam-text.g
===================================================================
--- trunk/seam-text.g	2008-07-16 12:27:07 UTC (rev 8469)
+++ trunk/seam-text.g	2008-07-16 12:27:54 UTC (rev 8470)
@@ -19,6 +19,28 @@
         }
     }
 
+     public class HtmlRecognitionException extends RecognitionException {
+         Token openingElement;
+         RecognitionException wrappedException;
+
+         public HtmlRecognitionException(Token openingElement, RecognitionException wrappedException) {
+             this.openingElement = openingElement;
+             this.wrappedException = wrappedException;
+         }
+
+         public Token getOpeningElement() {
+             return openingElement;
+         }
+
+         public String getMessage() {
+             return wrappedException.getMessage();
+         }
+
+         public Throwable getCause() {
+             return wrappedException;
+         }
+     }
+
     /**
      * Sanitization of user input, used to clean links and plain HTML.
      */
@@ -27,10 +49,11 @@
         /**
          * Called by the SeamTextParser when a link tag is parsed, i.e. [=>some URI].
          *
+         * @param element the token of the parse tree, here the ">" symbol which comes after the "="
          * @param uri the user-entered link text
          * @throws SemanticException thrown if the URI is not syntactically or semantically valid
          */
-        public void validateLinkTagURI(String uri) throws SemanticException;
+        public void validateLinkTagURI(Token element, String uri) throws SemanticException;
 
         /**
          * Called by the SeamTextParser when a plain HTML element is parsed.
@@ -230,9 +253,9 @@
             "tel", "telnet", "urn", "webcal", "wtai", "xmpp"
         ));
 
-        public void validateLinkTagURI(String uri) throws SemanticException {
+        public void validateLinkTagURI(Token element, String uri) throws SemanticException {
             if (!validateURI(uri)) {
-                throw new SemanticException("Invalid URI");
+                throw createSemanticException("Invalid URI", element);
             }
         }
 
@@ -242,7 +265,7 @@
             if (!acceptableElements.contains(elementName) &&
                 !svgElements.contains(elementName) &&
                 !mathmlElements.contains(elementName)) {
-                throw new SemanticException(getInvalidElementMessage(elementName));
+                throw createSemanticException(getInvalidElementMessage(elementName), element);
             }
         }
 
@@ -252,7 +275,7 @@
             if (!acceptableAttributes.contains(attributeName) &&
                 !svgAttributes.contains(attributeName) &&
                 !mathmlAttributes.contains(attributeName)) {
-                throw new SemanticException(getInvalidAttributeMessage(elementName, attributeName));
+                throw createSemanticException(getInvalidAttributeMessage(elementName, attributeName), element);
             }
         }
 
@@ -267,20 +290,26 @@
 
             // Check element with attribute that has URI value (href, src, etc.)
             if (attributesWhoseValueIsAURI.contains(attributeName) && !validateURI(attributeValue)) {
-                throw new SemanticException(getInvalidURIMessage(attributeValue));
+                throw createSemanticException(getInvalidURIMessage(attributeValue), element);
             }
 
             // Check attribute value of style (CSS filtering)
             if (attributeName.equals("style")) {
                 if (!REGEX_VALID_CSS_STRING1.matcher(attributeValue).matches() ||
                     !REGEX_VALID_CSS_STRING2.matcher(attributeValue).matches()) {
-                    throw new SemanticException(getInvalidAttributeValueMessage(elementName, attributeName, attributeValue));
+                    throw createSemanticException(
+                        getInvalidAttributeValueMessage(elementName, attributeName, attributeValue),
+                        element
+                    );
                 }
 
                 String[] cssProperties = attributeValue.split(";");
                 for (String cssProperty : cssProperties) {
                     if (!cssProperty.contains(":")) {
-                        throw new SemanticException(getInvalidAttributeValueMessage(elementName, attributeName, attributeValue));
+                        throw createSemanticException(
+                            getInvalidAttributeValueMessage(elementName, attributeName, attributeValue),
+                            element
+                        );
                     }
                     String[] property = cssProperty.split(":");
                     String propertyName = property[0].trim();
@@ -289,14 +318,20 @@
                     // CSS property name
                     if (!styleProperties.contains(propertyName) &&
                         !svgStyleProperties.contains(propertyName)) {
-                        throw new SemanticException(getInvalidAttributeValueMessage(elementName, attributeName, attributeValue));
+                        throw createSemanticException(
+                            getInvalidAttributeValueMessage(elementName, attributeName, attributeValue),
+                            element
+                        );
                     }
 
                     // CSS property value
                     if (propertyValue != null && !stylePropertiesValues.contains(propertyValue)) {
                         // Not in list, now check the regex
                         if (!REGEX_VALID_CSS_VALUE.matcher(propertyValue).matches()) {
-                            throw new SemanticException(getInvalidAttributeValueMessage(elementName, attributeName, attributeValue));
+                            throw createSemanticException(
+                                getInvalidAttributeValueMessage(elementName, attributeName, attributeValue),
+                                element
+                            );
                         }
                     }
                 }
@@ -351,6 +386,13 @@
             return "invalid value of attribute '" + attributeName + "' for element '" + elementName + "'";
         };
 
+        public SemanticException createSemanticException(String message, Token element) {
+            return new SemanticException(
+                message,
+                element.getFilename(), element.getLine(), element.getColumn()
+            );
+        }
+
     }
 
     private Sanitizer sanitizer = new DefaultSanitizer();
@@ -522,12 +564,12 @@
       { beginCapture(); } 
       (word|punctuation|escape|space)*
       { String text=endCapture(); } 
-      EQ GT 
+      EQ gt:GT
       { beginCapture(); }
       attributeValue 
       {
          String link = endCapture();
-         sanitizer.validateLinkTagURI(link);
+         sanitizer.validateLinkTagURI(gt, link);
          append(linkTag(text, link));
       }
       CLOSE
@@ -665,7 +707,7 @@
 newlineOrEof: newline | EOF
     ;
 
-html: openTag ( space | space attribute )* ( ( beforeBody body closeTagWithBody ) | closeTagWithNoBody ) 
+html: openTag ( space | space attribute )* ( ( beforeBody body closeTagWithBody ) | closeTagWithNoBody )
     ;
 
 body: (plain|formatted|preformatted|quoted|html|list|newline)*
@@ -680,10 +722,34 @@
          append(name.getText());
       }
     ;
+    exception // for rule
+        catch [RecognitionException ex] {
+            // We'd like to have an error reported that names the opening HTML, this
+            // helps users to find the actual start of their problem in the wiki text.
+            if (htmlElementStack.isEmpty()) throw ex;
+            Token tok = htmlElementStack.peek();
+            if (tok != null) {
+                throw new HtmlRecognitionException(tok, ex);
+            } else {
+                throw ex;
+            }
+        }
 
 beforeBody: GT { append(">"); }
     ;
-    
+    exception // for rule
+        catch [RecognitionException ex] {
+            // We'd like to have an error reported that names the opening HTML, this
+            // helps users to find the actual start of their problem in the wiki text.
+            if (htmlElementStack.isEmpty()) throw ex;
+            Token tok = htmlElementStack.peek();
+            if (tok != null) {
+                throw new HtmlRecognitionException(tok, ex);
+            } else {
+                throw ex;
+            }
+        }
+
 closeTagWithBody:
       LT SLASH name:ALPHANUMERICWORD GT
       {
@@ -701,7 +767,7 @@
          htmlElementStack.pop();
       }
     ;
-    
+
 attribute: att:ALPHANUMERICWORD (space)* EQ (space)*
            DOUBLEQUOTE
            {
@@ -720,14 +786,38 @@
            }
            DOUBLEQUOTE { append("\""); }
     ;
-        
+    exception // for rule
+        catch [RecognitionException ex] {
+            // We'd like to have an error reported that names the opening HTML, this
+            // helps users to find the actual start of their problem in the wiki text.
+            if (htmlElementStack.isEmpty()) throw ex;
+            Token tok = htmlElementStack.peek();
+            if (tok != null) {
+                throw new HtmlRecognitionException(tok, ex);
+            } else {
+                throw ex;
+            }
+        }
+
 attributeValue: ( AMPERSAND { append("&"); } |
                 an:ALPHANUMERICWORD { append( an.getText() ); } |
                 p:PUNCTUATION { append( p.getText() ); } |
                 s:SLASH { append( s.getText() ); } |
                 space | specialChars )*
     ;
-    
+    exception // for rule
+        catch [RecognitionException ex] {
+            // We'd like to have an error reported that names the opening HTML, this
+            // helps users to find the actual start of their problem in the wiki text.
+            if (htmlElementStack.isEmpty()) throw ex;
+            Token tok = htmlElementStack.peek();
+            if (tok != null) {
+                throw new HtmlRecognitionException(tok, ex);
+            } else {
+                throw ex;
+            }
+        }
+
 class SeamTextLexer extends Lexer;
 options
 {
@@ -744,10 +834,18 @@
 // '\u0250'..'\ufaff'  Various other languages, punctuation etc. (excluding "presentation forms")
 // '\uff00'..'\uffef'  Halfwidth and Fullwidth forms (including CJK punctuation)
 
-ALPHANUMERICWORD: ('a'..'z'|'A'..'Z'|'0'..'9')+
+ALPHANUMERICWORD
+    options {
+        paraphrase = "letters or digits";
+    }
+    :   ('a'..'z'|'A'..'Z'|'0'..'9')+
     ;
 
-UNICODEWORD: (
+UNICODEWORD
+    options {
+        paraphrase = "letters or digits";
+    }
+    : (
          '\u00a0'..'\u00ff' |
          '\u0100'..'\u017f' |
          '\u0180'..'\u024f' |
@@ -756,68 +854,158 @@
       )+
     ;
 
-PUNCTUATION: '-' | ';' | ':' | '(' | ')' | '{' | '}' | '?' | '!' | '@' | '%' | '.' | ',' | '$'
+PUNCTUATION
+    options {
+        paraphrase = "a punctuation character";
+    }
+    : '-' | ';' | ':' | '(' | ')' | '{' | '}' | '?' | '!' | '@' | '%' | '.' | ',' | '$'
     ;
     
-EQ: '='
+EQ
+    options {
+        paraphrase = "an equals '='";
+    }
+    : '='
     ;
     
-PLUS: '+'
+PLUS
+    options {
+        paraphrase = "a plus '+'";
+    }
+    : '+'
     ;
     
-UNDERSCORE: '_'
+UNDERSCORE
+    options {
+        paraphrase = "an underscore '_'";
+    }
+    : '_'
     ;
 
-STAR: '*'
+STAR
+    options {
+        paraphrase = "a star '*'";
+    }
+    : '*'
     ;
 
-SLASH: '/'
+SLASH
+    options {
+        paraphrase = "a slash '/'";
+    }
+
+    : '/'
     ;
 
-ESCAPE: '\\'
+ESCAPE
+    options {
+        paraphrase = "the escaping blackslash '\'";
+    }
+    : '\\'
     ;
     
-BAR: '|'
+BAR
+    options {
+        paraphrase = "a bar or pipe '|'";
+    }
+    : '|'
     ;
     
-BACKTICK: '`'
+BACKTICK
+    options {
+        paraphrase = "a backtick '`'";
+    }
+    : '`'
     ;
     
-TWIDDLE: '~'
+    
+TWIDDLE
+    options {
+        paraphrase = "a tilde '~'";
+    }
+    : '~'
     ;
 
-DOUBLEQUOTE: '"'
+DOUBLEQUOTE
+    options {
+        paraphrase = "a doublequote \"";
+    }
+    : '"'
     ;
 
-SINGLEQUOTE: '\''
+SINGLEQUOTE
+    options {
+        paraphrase = "a single quote '";
+    }
+    : '\''
     ;
 
-OPEN: '['
+OPEN
+    options {
+        paraphrase = "an opening square bracket '['";
+    }
+    : '['
     ;
     
-CLOSE: ']'
+CLOSE
+    options {
+        paraphrase = "a closing square bracket ']'";
+    }
+    : ']'
     ;
 
-HASH: '#'
+HASH
+    options {
+        paraphrase = "a hash '#'";
+    }
+    : '#'
     ;
     
-HAT: '^'
+HAT
+    options {
+        paraphrase = "a caret '^'";
+    }
+    : '^'
     ;
     
-GT: '>'
+GT
+    options {
+        paraphrase = "a closing angle bracket '>'";
+    }
+    : '>'
     ;
     
-LT: '<'
+LT
+    options {
+        paraphrase = "an opening angle bracket '<'";
+    }
+    : '<'
     ;
 
-AMPERSAND: '&'
+AMPERSAND
+    options {
+        paraphrase = "an ampersand '&'";
+    }
+    : '&'
     ;
 
-SPACE: (' '|'\t')+
+SPACE
+    options {
+        paraphrase = "a space or tab";
+    }
+    : (' '|'\t')+
     ;
     
-NEWLINE: "\r\n" | '\r' | '\n'
+NEWLINE
+    options {
+        paraphrase = "a newline";
+    }
+    : "\r\n" | '\r' | '\n'
     ;
 
-EOF : '\uFFFF'
+EOF
+    options {
+        paraphrase = "the end of the text";
+    }
+    : '\uFFFF'
     ;




More information about the seam-commits mailing list