You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by vm...@apache.org on 2008/01/18 09:40:41 UTC

svn commit: r613103 - in /maven/sandbox/trunk/doxia/doxia-module-xwiki/src: main/java/org/apache/maven/doxia/module/xwiki/parser/ test/java/org/apache/maven/doxia/module/xwiki/parser/

Author: vmassol
Date: Fri Jan 18 00:40:40 2008
New Revision: 613103

URL: http://svn.apache.org/viewvc?rev=613103&view=rev
Log:
DOXIA-200: Add a Parser for XWiki

* Macro parsing should now work fine for most cases

Modified:
    maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroBlock.java
    maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroParser.java
    maven/sandbox/trunk/doxia/doxia-module-xwiki/src/test/java/org/apache/maven/doxia/module/xwiki/parser/MacroParserTest.java

Modified: maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroBlock.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroBlock.java?rev=613103&r1=613102&r2=613103&view=diff
==============================================================================
--- maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroBlock.java (original)
+++ maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroBlock.java Fri Jan 18 00:40:40 2008
@@ -3,9 +3,9 @@
 import org.apache.maven.doxia.module.confluence.parser.AbstractFatherBlock;
 import org.apache.maven.doxia.sink.Sink;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.HashMap;
 
 public class MacroBlock
     extends AbstractFatherBlock
@@ -15,7 +15,7 @@
     private Map parameters;
 
     private String content;
-    
+
     public MacroBlock( String name, Map parameters, String content, List childBlocks )
     {
         super( childBlocks );
@@ -41,7 +41,7 @@
 
     public Map getParameters()
     {
-        Map newParameters = new HashMap(this.parameters);
+        Map newParameters = new HashMap( this.parameters );
         return newParameters;
     }
 

Modified: maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroParser.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroParser.java?rev=613103&r1=613102&r2=613103&view=diff
==============================================================================
--- maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroParser.java (original)
+++ maven/sandbox/trunk/doxia/doxia-module-xwiki/src/main/java/org/apache/maven/doxia/module/xwiki/parser/MacroParser.java Fri Jan 18 00:40:40 2008
@@ -11,7 +11,22 @@
  * This class was written with performance in mind and thus is lacking clarity. Since this code is
  * in the rendering path it's important it be very fast.
  * <p/>
- * NOTE: Do NOT use this parser yet as it's not ready and not working.
+ * TODO: Compare speed with using regex. For example, something like this:
+ * <pre><code>
+ *         Pattern p = Pattern.compile("(?:(.*)(?::)?)?(.*)?(?:/)}(?:(.*)\\{(?:\\/)\1})?");
+ * <p/>
+ *         Matcher m = p.matcher(macro);
+ *         m.find();
+ *         Map parameters = new HashMap();
+ *         if (m.group(2) != null && m.group(2).length() > 0) {
+ *             StringTokenizer st = new StringTokenizer(m.group(2), "|");
+ *             while (st.hasMoreTokens()) {
+ *                 String param = st.nextToken();
+ *                 StringTokenizer st2 = new StringTokenizer(param, "=");
+ *                 parameters.put(st2.nextToken(), st2.nextToken());
+ *             }
+ *          }
+ * </code></pre>
  */
 public class MacroParser
 {
@@ -81,14 +96,17 @@
                     break;
                     // {macroname:... /}. Contraction of {macroname:...}{/macroname}
                 case '/':
-                    if ( state == STATE_PARAM_VALUE || state == STATE_NAME)
+                    if ( state == STATE_PARAM_VALUE || state == STATE_NAME )
                     {
                         if ( charAt( input, i ) == '}' )
                         {
                             i++;
-                            if (state == STATE_PARAM_VALUE) {
-                                parameters.put(parameterName, text.toString());
-                            } else {
+                            if ( state == STATE_PARAM_VALUE )
+                            {
+                                parameters.put( parameterName, text.toString() );
+                            }
+                            else
+                            {
                                 macroName = text.toString();
                             }
                             state = STATE_END;
@@ -99,9 +117,12 @@
                             text.append( c );
                         }
                     }
-                    else if (state == STATE_CONTENT) {
-                        text.append(c);
-                    } else {
+                    else if ( state == STATE_CONTENT )
+                    {
+                        text.append( c );
+                    }
+                    else
+                    {
                         throw new ParseException( "Invalid position for character '/' in Macro" );
                     }
                     break;
@@ -111,32 +132,48 @@
                     // * {newmacro..}...{/newmacro}
                     // * {oldsinglelinemacro:...}
                     // * {oldmultilinemacro:...}...{oldmultilinemacro}
-                    // * {oldmultilinemacro:...}...{/oldmultilinemacro}
-                    if ( state == STATE_PARAM_VALUE)
+                    if ( state == STATE_PARAM_VALUE )
                     {
-                        parameters.put(parameterName, text.toString());
+                        parameters.put( parameterName, text.toString() );
                         text = new StringBuffer();
 
                         // {macro:...}
                         if ( isInCompatibilityMode )
                         {
-                            // TODO
-                            throw new ParseException( "Compatibility mode for macros not implemented yet" );
+                            // Since we can't guess if a macro is a multiline one or a single line one we rely on
+                            // a static list of known multiline macros...
+                            if ( multilineMacros.contains( macroName ) )
+                            {
+                                state = STATE_CONTENT;
+                            }
+                            else
+                            {
+                                state = STATE_END;
+                            }
                         }
                         else
                         {
                             state = STATE_CONTENT;
                         }
                     }
-                    else if ( state == STATE_NAME) {
+                    else if ( state == STATE_NAME )
+                    {
                         macroName = text.toString();
                         text = new StringBuffer();
 
                         // {macro:...}
                         if ( isInCompatibilityMode )
                         {
-                            // TODO
-                            throw new ParseException( "Compatibility mode for macros not implemented yet" );
+                            // Since we can't guess if a macro is a multiline one or a single line one we rely on
+                            // a static list of known multiline macros...
+                            if ( multilineMacros.contains( macroName ) )
+                            {
+                                state = STATE_CONTENT;
+                            }
+                            else
+                            {
+                                state = STATE_END;
+                            }
                         }
                         else
                         {
@@ -172,10 +209,12 @@
                         content = text.toString();
                         i++;
                         char cc;
-                        do {
+                        do
+                        {
                             i++;
                             cc = input.charAt( i );
-                        } while ( cc != '}' && i < input.length() );
+                        }
+                        while ( cc != '}' && i < input.length() );
                         state = STATE_END;
                     }
                     else
@@ -189,8 +228,23 @@
                         {
                             if ( isInCompatibilityMode )
                             {
-                                // TODO
-                                throw new ParseException( "Compatibility mode for macros not implemented yet" );
+                                // Allow closing macros without using the '/' character
+                                // TODO: Add special support for code macros nested in other code macros and for
+                                // style macros nested in other style macros.
+
+                                // Verify that the following characters are the name of the macro and thus that this
+                                // '}' is the beginning of the macro closing.
+                                int pos = input.indexOf( macroName + "}", i + 1 );
+                                if ( pos == i + 1 )
+                                {
+                                    state = STATE_END;
+                                    i += macroName.length() + 1;
+                                    content = text.toString();
+                                }
+                                else
+                                {
+                                    text.append( c );
+                                }
                             }
                             else
                             {
@@ -207,7 +261,7 @@
                     // supported too in param values.
                     if ( state == STATE_PARAM_VALUE )
                     {
-                        parameters.put(parameterName, text.toString());
+                        parameters.put( parameterName, text.toString() );
                         text = new StringBuffer();
                         state = STATE_PARAM_NAME;
                     }
@@ -237,13 +291,27 @@
                     }
                     break;
                 default:
-                    text.append( c );
+                    // Any non alphanumeric character found when parsing the macro name should stop the parsing since
+                    // it means the text being parsed is not a macro.
+                    if ( ( state == STATE_NAME ) && ( ( c < 'a' || c > 'z' ) && ( c < 'A' || c > 'Z' ) ) )
+                    {
+                        // Invalid macro, exit
+                        state = STATE_END;
+                        i = position - 1;
+                    }
+                    else
+                    {
+                        text.append( c );
+                    }
             }
 
             i++;
         }
 
-        blocks.add( new MacroBlock( macroName, parameters, content, new ArrayList() ) );
+        if ( macroName != null )
+        {
+            blocks.add( new MacroBlock( macroName, parameters, content, new ArrayList() ) );
+        }
 
         return i;
     }

Modified: maven/sandbox/trunk/doxia/doxia-module-xwiki/src/test/java/org/apache/maven/doxia/module/xwiki/parser/MacroParserTest.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/doxia/doxia-module-xwiki/src/test/java/org/apache/maven/doxia/module/xwiki/parser/MacroParserTest.java?rev=613103&r1=613102&r2=613103&view=diff
==============================================================================
--- maven/sandbox/trunk/doxia/doxia-module-xwiki/src/test/java/org/apache/maven/doxia/module/xwiki/parser/MacroParserTest.java (original)
+++ maven/sandbox/trunk/doxia/doxia-module-xwiki/src/test/java/org/apache/maven/doxia/module/xwiki/parser/MacroParserTest.java Fri Jan 18 00:40:40 2008
@@ -5,7 +5,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class MacroParserTest extends TestCase
+public class MacroParserTest
+    extends TestCase
 {
     private MacroParser parser;
 
@@ -14,76 +15,125 @@
         parser = new MacroParser();
     }
 
-    public void testParseSimplestMacroWithCondensedClosingStyle() throws Exception
+    public void testParseSimplestMacroWithCondensedClosingStyle()
+        throws Exception
     {
         List blocks = new ArrayList();
         String macro = "{macro/}";
-        int pos = parser.parse( macro + " ...", 1, blocks);
+        int pos = parser.parse( macro + " ...", 1, blocks );
 
-        assertEquals(macro.length(), pos);
-        assertEquals(1, blocks.size());
-        MacroBlock macroBlock = (MacroBlock) blocks.get(0);
-        assertEquals("macro", macroBlock.getName());
-        assertEquals("", macroBlock.getContent());
-        assertTrue(macroBlock.getParameters().isEmpty());
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "macro", macroBlock.getName() );
+        assertEquals( "", macroBlock.getContent() );
+        assertTrue( macroBlock.getParameters().isEmpty() );
     }
 
-    public void testParseSimplestMacroWithExpandedClosingStyle() throws Exception
+    public void testParseSimplestMacroWithExpandedClosingStyle()
+        throws Exception
     {
         List blocks = new ArrayList();
         String macro = "{macro}{/macro}";
-        int pos = parser.parse( macro + " ...", 1, blocks);
+        int pos = parser.parse( macro + " ...", 1, blocks );
 
-        assertEquals(macro.length(), pos);
-        assertEquals(1, blocks.size());
-        MacroBlock macroBlock = (MacroBlock) blocks.get(0);
-        assertEquals("macro", macroBlock.getName());
-        assertEquals("", macroBlock.getContent());
-        assertTrue(macroBlock.getParameters().isEmpty());
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "macro", macroBlock.getName() );
+        assertEquals( "", macroBlock.getContent() );
+        assertTrue( macroBlock.getParameters().isEmpty() );
     }
 
-    public void testParseMacroWithOneParameter() throws Exception
+    public void testParseMacroWithOneParameter()
+        throws Exception
     {
         List blocks = new ArrayList();
         String macro = "{macro:param1=value1/}";
-        int pos = parser.parse( macro + " ...", 1, blocks);
+        int pos = parser.parse( macro + " ...", 1, blocks );
 
-        assertEquals(macro.length(), pos);
-        assertEquals(1, blocks.size());
-        MacroBlock macroBlock = (MacroBlock) blocks.get(0);
-        assertEquals("macro", macroBlock.getName());
-        assertEquals("", macroBlock.getContent());
-        assertEquals(1, macroBlock.getParameters().size());
-        assertEquals("value1", macroBlock.getParameters().get("param1"));
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "macro", macroBlock.getName() );
+        assertEquals( "", macroBlock.getContent() );
+        assertEquals( 1, macroBlock.getParameters().size() );
+        assertEquals( "value1", macroBlock.getParameters().get( "param1" ) );
     }
 
-    public void testParseMacroWithSeveralParameters() throws Exception
+    public void testParseMacroWithSeveralParameters()
+        throws Exception
     {
         List blocks = new ArrayList();
         String macro = "{macro:param1=value1|param2=value2/}";
-        int pos = parser.parse( macro + " ...", 1, blocks);
+        int pos = parser.parse( macro + " ...", 1, blocks );
 
-        assertEquals(macro.length(), pos);
-        assertEquals(1, blocks.size());
-        MacroBlock macroBlock = (MacroBlock) blocks.get(0);
-        assertEquals("macro", macroBlock.getName());
-        assertEquals("", macroBlock.getContent());
-        assertEquals(2, macroBlock.getParameters().size());
-        assertEquals("value1", macroBlock.getParameters().get("param1"));
-        assertEquals("value2", macroBlock.getParameters().get("param2"));
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "macro", macroBlock.getName() );
+        assertEquals( "", macroBlock.getContent() );
+        assertEquals( 2, macroBlock.getParameters().size() );
+        assertEquals( "value1", macroBlock.getParameters().get( "param1" ) );
+        assertEquals( "value2", macroBlock.getParameters().get( "param2" ) );
     }
 
-    public void testParseMacroWithContent() throws Exception
+    public void testParseMacroWithContent()
+        throws Exception
     {
         List blocks = new ArrayList();
         String macro = "{macro}Some /=|content{/macro}";
-        int pos = parser.parse( macro + " ...", 1, blocks);
+        int pos = parser.parse( macro + " ...", 1, blocks );
 
-        assertEquals(macro.length(), pos);
-        assertEquals(1, blocks.size());
-        MacroBlock macroBlock = (MacroBlock) blocks.get(0);
-        assertEquals("macro", macroBlock.getName());
-        assertEquals("Some /=|content", macroBlock.getContent());
-        assertEquals(0, macroBlock.getParameters().size());
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "macro", macroBlock.getName() );
+        assertEquals( "Some /=|content", macroBlock.getContent() );
+        assertEquals( 0, macroBlock.getParameters().size() );
+    }
+
+    public void testParseMacroWithInvalidMacroName()
+        throws Exception
+    {
+        List blocks = new ArrayList();
+        // This is not a macro. It should be ignored and no macro block should be created
+        String macro = "{[link]/}";
+        int pos = parser.parse( macro + " ...", 1, blocks );
+
+        assertEquals( 1, pos );
+        assertEquals( 0, blocks.size() );
+    }
+
+    public void testParseOldStyleMacroInCompatibilityModeWhenMultilineMacro()
+        throws Exception
+    {
+        parser.setCompatibilityMode( true );
+        List blocks = new ArrayList();
+        String macro = "{code}Some content here{code}";
+        int pos = parser.parse( macro + " ...", 1, blocks );
+
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "code", macroBlock.getName() );
+        assertEquals( "Some content here", macroBlock.getContent() );
+        assertEquals( 0, macroBlock.getParameters().size() );
+    }
+
+    public void testParseOldStyleMacroInCompatibilityModeWhenSinglelineMacro()
+        throws Exception
+    {
+        parser.setCompatibilityMode( true );
+        List blocks = new ArrayList();
+        String macro = "{somesinglelinemacro}";
+        int pos = parser.parse( macro + " ...", 1, blocks );
+
+        assertEquals( macro.length(), pos );
+        assertEquals( 1, blocks.size() );
+        MacroBlock macroBlock = (MacroBlock) blocks.get( 0 );
+        assertEquals( "somesinglelinemacro", macroBlock.getName() );
+        assertEquals( "", macroBlock.getContent() );
+        assertEquals( 0, macroBlock.getParameters().size() );
     }
 }