All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.wiki.engine.creole.parser.parser.Creole10.g Maven / Gradle / Ivy

The newest version!
grammar Creole10;

options {
	language=Java;
}

tokens {
  FORCED_END_OF_LINE;
  HEADING_SECTION;
  HORIZONTAL_SECTION;
  LIST_ITEM;
  LIST_ITEM_PART;
  NOWIKI_SECTION;
  SCAPE_NODE;
  TEXT_NODE;
  UNORDERED_LIST;
  UNFORMATTED_TEXT;
  WIKI;
}

scope CountLevel {
  int level;
  String currentMarkup;
  String groups;
}

@header {
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.wiki.engine.creole.parser.parser;

import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.wiki.engine.creole.parser.ast.ASTNode;
import com.liferay.wiki.engine.creole.parser.ast.BaseListNode;
import com.liferay.wiki.engine.creole.parser.ast.BaseParentableNode;
import com.liferay.wiki.engine.creole.parser.ast.BoldTextNode;
import com.liferay.wiki.engine.creole.parser.ast.CollectionNode;
import com.liferay.wiki.engine.creole.parser.ast.ForcedEndOfLineNode;
import com.liferay.wiki.engine.creole.parser.ast.FormattedTextNode;
import com.liferay.wiki.engine.creole.parser.ast.HeadingNode;
import com.liferay.wiki.engine.creole.parser.ast.HorizontalNode;
import com.liferay.wiki.engine.creole.parser.ast.ImageNode;
import com.liferay.wiki.engine.creole.parser.ast.ItalicTextNode;
import com.liferay.wiki.engine.creole.parser.ast.ItemNode;
import com.liferay.wiki.engine.creole.parser.ast.LineNode;
import com.liferay.wiki.engine.creole.parser.ast.ListNode;
import com.liferay.wiki.engine.creole.parser.ast.NoWikiSectionNode;
import com.liferay.wiki.engine.creole.parser.ast.OrderedListItemNode;
import com.liferay.wiki.engine.creole.parser.ast.OrderedListNode;
import com.liferay.wiki.engine.creole.parser.ast.ParagraphNode;
import com.liferay.wiki.engine.creole.parser.ast.ScapedNode;
import com.liferay.wiki.engine.creole.parser.ast.UnformattedTextNode;
import com.liferay.wiki.engine.creole.parser.ast.UnorderedListItemNode;
import com.liferay.wiki.engine.creole.parser.ast.UnorderedListNode;
import com.liferay.wiki.engine.creole.parser.ast.WikiPageNode;
import com.liferay.wiki.engine.creole.parser.ast.extension.TableOfContentsNode;
import com.liferay.wiki.engine.creole.parser.ast.link.LinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.C2InterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.DokuWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.FlickrInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.GoogleInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.InterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.JSPWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.MeatballInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.MediaWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.MoinMoinInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.OddmuseInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.OhanaInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.PmWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.PukiWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.PurpleWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.RadeoxInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.SnipSnapInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.TWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.TiddlyWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.UsemodInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.WikipediaInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.link.interwiki.XWikiInterwikiLinkNode;
import com.liferay.wiki.engine.creole.parser.ast.table.TableCellNode;
import com.liferay.wiki.engine.creole.parser.ast.table.TableDataNode;
import com.liferay.wiki.engine.creole.parser.ast.table.TableHeaderNode;
import com.liferay.wiki.engine.creole.parser.ast.table.TableNode;

import java.util.Stack;

/**
* This is a generated file from Creole10.g. DO NOT MODIFY THIS FILE MANUALLY!!
* If needed, modify the grammar and rerun the gradle generation task
* (../../../../gradlew generateGrammarSource)
*/
}

@lexer::header {
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

 package com.liferay.wiki.engine.creole.parser.parser;
}

@members{
	public void displayRecognitionError(String[] tokenNames,RecognitionException e) {
		String header = getErrorHeader(e);
		String message = getErrorMessage(e, tokenNames);

		_errors.add(header + " " + message);
	}

	public List getErrors() {
		return _errors;
	}

	public WikiPageNode getWikiPageNode() {
		if (_wikipage == null)
			throw new IllegalStateException("No successful parsing process");

		return _wikipage;
	}

	protected static final String GROUPING_SEPARATOR = "-";

	protected BaseParentableNode buildAndComposeListNode(BaseParentableNode baseParentableNode, ItemNode itemNode, boolean ordered) {
		BaseParentableNode listNode = null;
		
		if (ordered) {
			listNode = new OrderedListNode(baseParentableNode);
		} 
		else {
		 	listNode = new UnorderedListNode(baseParentableNode);
		}

		itemNode.setBaseParentableNode(listNode);
		listNode.addChildASTNode(itemNode);

		baseParentableNode.addChildASTNode(listNode);

		return listNode;
	}

	private List _errors = new ArrayList();
	private WikiPageNode _wikipage;

}

wikipage
	:	( whitespaces )?  p=paragraphs  { _wikipage = new WikiPageNode($p.sections); } EOF
	;
paragraphs returns [CollectionNode sections = new CollectionNode()]
	:	(p= paragraph {
			if ($p.node != null){ // at this moment we ignore paragraps with blanks
				$sections.add($p.node);
			}
			} )*
	;
paragraph returns [ASTNode node = null]
	:	n=nowiki_block { $node = $n.nowikiNode; }
	|	blanks  paragraph_separator
	|	( blanks )?
			(	tof = table_of_contents {$node = $tof.tableOfContents;}
			|	h =  heading { $node = $h.header;}
			|	{ input.LA(1) == DASH && input.LA(2) == DASH &&
				input.LA(3) == DASH && input.LA(4) == DASH }?
				hn = horizontalrule {$node = $hn.horizontal;}
			|	l = list {$node = $l.listNode;}
			|	t = table { $node = $t.table; }
			|	tp = text_paragraph  {$node = $tp.paragraph; }
			)  ( paragraph_separator )?
	;



///////////////////////   T E X T  P A R A G R A P H   ////////////////////////

text_paragraph returns [ ParagraphNode paragraph = new ParagraphNode() ]
	:	(	tl = text_line {  $paragraph.addChildASTNode($tl.line);  }
		|	( NOWIKI_OPEN  ~( NEWLINE ) )  =>
			nw = nowiki_inline  {$paragraph.addChildASTNode($nw.nowiki);} ( te = text_element  {$paragraph.addChildASTNode($te.item);} )*  text_lineseparator
		)+
	;
text_line returns [LineNode line = new LineNode()]
	:	first = text_firstelement  {
										if ($first.item != null) { // recovering from errors
											$line.addChildASTNode($first.item);
										}
									}
								( element = text_element  {
								if ($element.item != null) // recovering from errors
									$line.addChildASTNode($element.item);
							}
					)*  text_lineseparator
	;
text_firstelement returns [ASTNode item = null]
	:	{ input.LA(1) != STAR || (input.LA(1) == STAR && input.LA(2) == STAR) }?
		tf = text_formattedelement { $item = $tf.item; }
	|	tu = text_first_unformattedelement { $item = $tu.item; }
	;
text_formattedelement returns [FormattedTextNode item = null]
	:	ital_markup  ic =text_italcontent  { $item = new ItalicTextNode($ic.text); } ( ( NEWLINE )?  ital_markup )?
	|	bold_markup  bc = text_boldcontent  {$item = new BoldTextNode($bc.text); } ( ( NEWLINE )?  bold_markup )?
	;
text_boldcontent returns [ CollectionNode text = new CollectionNode() ]
	:	( NEWLINE )?  ( p = text_boldcontentpart  { $text.add($p.node); } )*
	|	EOF
	;
text_italcontent returns [ CollectionNode text = new CollectionNode() ]
	:	( NEWLINE )?  ( p = text_italcontentpart  { $text.add($p.node); } )*
	|	EOF
	;
text_element returns [ASTNode item = null]
	:	onestar  tu1 = text_unformattedelement { $item = $tu1.contents; }
	|	tu2 = text_unformattedelement  onestar { $item = $tu2.contents; }
	|	tf = text_formattedelement { $item = $tf.item; }
	;

text_boldcontentpart returns [FormattedTextNode node = null]
	:	ital_markup  t = text_bolditalcontent  {$node = new ItalicTextNode($t.items); } ( ital_markup )?
	|	tf = text_formattedcontent {$node = new FormattedTextNode($tf.items); }
	;
text_italcontentpart returns [FormattedTextNode node = null]
	:	bold_markup  t = text_bolditalcontent { $node = new BoldTextNode($t.items); } ( bold_markup )?
	|	tf =text_formattedcontent {$node = new FormattedTextNode($tf.items); }
	;
text_bolditalcontent returns [ASTNode items = null]
	:	( NEWLINE )?  ( tf =text_formattedcontent {$items = $tf.items; } )?
	|	EOF
	;
text_formattedcontent returns [CollectionNode items = new CollectionNode ()]
	:	onestar  ( t = text_unformattedelement  {$items.add($t.contents); } onestar  ( text_linebreak )? )+
	;
text_linebreak
	:	{ input.LA(2) != DASH && input.LA(2) != POUND &&
		input.LA(2) != EQUAL && input.LA(2) != NEWLINE }?
		text_lineseparator
	;
text_inlineelement returns [ASTNode element = null ]
	:	tf = text_first_inlineelement {$element = $tf.element; }
	|	nwi = nowiki_inline {$element = $nwi.nowiki; }
	;
text_first_inlineelement  returns [ASTNode element = null]
	:
		l=link {$element = $l.link;}
	|	i = image {$element = $i.image;}
	|	e= extension {$element = $e.node;}
	;
text_first_unformattedelement returns [ASTNode item = null]
	:	tfu = text_first_unformatted {$item = new UnformattedTextNode($tfu.items);}
	|	tfi = text_first_inlineelement { $item = $tfi.element; }
	;
text_first_unformatted returns [CollectionNode items = new CollectionNode()]
	:	 	t = text_first_unformmatted_text {$items.add(new UnformattedTextNode($t.text.toString()));}
		|	(forced_linebreak { $items.add(new ForcedEndOfLineNode()); }
		|	e = escaped {$items.add($e.scaped);} )+
	;

text_first_unformmatted_text returns [StringBundler text = new StringBundler()]
	:
	 (c =  ~(	POUND
			|	STAR
			|	EQUAL
			|	PIPE
			|	ITAL
			|	LINK_OPEN
			|	IMAGE_OPEN
			|	NOWIKI_OPEN
			|	EXTENSION
			|	FORCED_LINEBREAK
			|	ESCAPE
			|	NEWLINE
			|	EOF ) {$text.append($c.text); } )  +
	;
text_unformattedelement returns [ASTNode contents = null]
	:	text = text_unformatted { $contents = $text.items; }
	|	ti = text_inlineelement { $contents = $ti.element; }
	;

text_unformatted returns [CollectionNode items = new CollectionNode()]
	:		contents = text_unformated_text {$items.add(new UnformattedTextNode($contents.text.toString())); }
		|	(forced_linebreak { $items.add(new ForcedEndOfLineNode()); }
		|	e = escaped {$items.add($e.scaped);} )+
	;

text_unformated_text returns [StringBundler text = new StringBundler()]
:
	(c = ~(	ITAL
			|	STAR
			|	LINK_OPEN
			|	IMAGE_OPEN
			|	NOWIKI_OPEN
			|	EXTENSION
			|	FORCED_LINEBREAK
			|	ESCAPE
			|	NEWLINE
			|	EOF ) { $text.append($c.text);} ) +
	;

//////////////////////////////   H E A D I N G   //////////////////////////////

heading returns [ASTNode header]
	scope {
	       CollectionNode items;
	       int nestedLevel;
	       String text;
	}
	@init {
		$heading::items = new CollectionNode();
		$heading::text = new String();
	}
	:	heading_markup  {$heading::nestedLevel++;} heading_content { $header = new HeadingNode($heading::items,$heading::nestedLevel); }  ( heading_markup )?  ( blanks )?
		paragraph_separator
	;
heading_content
	:	heading_markup {$heading::nestedLevel++;}  heading_content  ( heading_markup )?
	|	ht = heading_text {$heading::items= $ht.items;}
	;

heading_text returns [CollectionNode items = null]
	:	te = heading_cellcontent {$items = $te.items;}
	;

heading_cellcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( tcp = heading_cellcontentpart  {

							if ($tcp.node != null) { // some AST Node could be NULL if bad CREOLE syntax is wrotten
								$items.add($tcp.node);
							}

							}
						onestar )*
	;
heading_cellcontentpart returns [ASTNode node = null]
	:	tf = heading_formattedelement {$node=$tf.content;}
	|	tu = heading_unformattedelement {$node=$tu.content;}
	;
heading_formattedelement returns [ASTNode content = null]
	:	ital_markup   ( tic = heading_italcontent { $content = new ItalicTextNode($tic.items); })?  ( ital_markup )?
	|	bold_markup ( tbc= heading_boldcontent  {$content = new BoldTextNode($tbc.items);})?  ( bold_markup )?
	;
heading_boldcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( tb = heading_boldcontentpart  { $items.add($tb.node); } onestar )+
	|	EOF
	;
heading_italcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( ti = heading_italcontentpart  { $items.add($ti.node); } onestar )+
	|	EOF
	;
heading_boldcontentpart returns [ASTNode node = null]
	:	tf = heading_formattedcontent {$node = $tf.elements; }
	|	ital_markup  tb = heading_bolditalcontent  { $node = new ItalicTextNode($tb.elements);  } ( ital_markup )?
	;
heading_italcontentpart returns [ASTNode node = null]
	:	bold_markup  tb = heading_bolditalcontent  {$node = new BoldTextNode($tb.elements); } ( bold_markup )?
	|	tf = heading_formattedcontent { $node = $tf.elements; }
	;
heading_bolditalcontent returns [CollectionNode elements = null]
	:	onestar  ( tfc = heading_formattedcontent  { $elements = $tfc.elements; } onestar )?
	|	EOF
	;
heading_formattedcontent returns [CollectionNode elements = new CollectionNode()]
	:	( tu = heading_unformattedelement { $elements.add($tu.content); } )+
	;
heading_unformattedelement returns [ASTNode content = null]
	:	tu = heading_unformatted_text  {$content = new UnformattedTextNode($tu.text.toString());}
	|	ti = heading_inlineelement {$content = $ti.element;}
	;
heading_inlineelement returns [ASTNode element = null]
	:	l = link {$element = $l.link; }
	|	i =image {$element = $i.image; }
	|	nwi = nowiki_inline {$element = $nwi.nowiki; }
	;

heading_unformatted_text returns [StringBundler text = new StringBundler()]
	:	( c = ~(LINK_OPEN | IMAGE_OPEN | NOWIKI_OPEN |EQUAL | ESCAPE | NEWLINE | EOF  )  {$text.append($c.text);} )+
	;


/////////////////////////////////   L I S T   /////////////////////////////////

list returns [ListNode listNode = null]
	scope {
		BaseListNode currentParent;
		ListNode root;
		Stack parents;
		int lastLevel = 1;
	}
	@init{
		$list::root = new ListNode();

		if (input.LA(1) == POUND) {
			$list::currentParent = new OrderedListNode($list::root);
		}
		else {
			$list::currentParent = new UnorderedListNode($list::root);
		}

		$list::root.addChildASTNode($list::currentParent);

		$list::parents = new Stack();
	}
	@after {
		$listNode = $list::root;
	}
	:	( elem = list_elems )+  ( end_of_list )?
	;

list_elems
	scope  CountLevel;
	@init{
		$CountLevel::level = 0;
	}
	:	om = list_ordelem_markup {++$CountLevel::level;$CountLevel::currentMarkup = $om.text;$CountLevel::groups += $om.text;}  
				elem=list_elem {  

					Stack parents = $list::parents;

					ItemNode top = parents.isEmpty()?null:parents.peek();

					BaseParentableNode baseParentableNode = $list::currentParent;

					if (top == null) {
						OrderedListItemNode node = new OrderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);
						baseParentableNode.addChildASTNode(node);

						parents.push(node);

					}
					else if ($CountLevel::level > $list::lastLevel) {		
						OrderedListNode orderedListNode = new OrderedListNode(top);

						OrderedListItemNode node = new OrderedListItemNode($CountLevel::level, orderedListNode, $elem.items);
						orderedListNode.addChildASTNode(node);

						top.addChildASTNode(orderedListNode);

						parents.push(node);
					} 
					else if ($CountLevel::level < $list::lastLevel) {
						ItemNode in = parents.peek();

						while (in.getLevel() > $CountLevel::level) {
							in = parents.pop();
							--$list::lastLevel;
						}

						top = in;

						baseParentableNode = top.getBaseParentableNode();

						OrderedListItemNode node = new OrderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);

						if (baseParentableNode instanceof UnorderedListItemNode) {
							buildAndComposeListNode(baseParentableNode, node, true);
						}
						else if (baseParentableNode instanceof UnorderedListNode) {
							baseParentableNode = ((UnorderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, true);
						}
						else if (baseParentableNode instanceof OrderedListNode && top instanceof UnorderedListItemNode) {
							baseParentableNode = ((OrderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, true);
						}
						else {
							baseParentableNode.addChildASTNode(node);
						}

						parents.push(node);

					}
					else {
						baseParentableNode = top.getBaseParentableNode();

						OrderedListItemNode node = new OrderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);

						if (baseParentableNode instanceof UnorderedListItemNode) {
							buildAndComposeListNode(baseParentableNode, node, true);
						} 
						else if (baseParentableNode instanceof UnorderedListNode) {
							baseParentableNode = ((UnorderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, true);
						} 
						else if (baseParentableNode instanceof OrderedListNode && top instanceof UnorderedListItemNode) {
							baseParentableNode = ((OrderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, true);
						} 
						else {
							baseParentableNode.addChildASTNode(node);
						}

						parents.pop();
						parents.push(node);
					}

					$list::lastLevel = $CountLevel::level;
				}
	|	um = list_unordelem_markup {++$CountLevel::level; $CountLevel::currentMarkup = $um.text;$CountLevel::groups += $um.text;}  
				elem=list_elem {

					Stack parents = $list::parents;

					ItemNode top = parents.isEmpty()?null:parents.peek();

					BaseParentableNode baseParentableNode = $list::currentParent;

					if (top == null) {
						UnorderedListItemNode node = new UnorderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);
						baseParentableNode.addChildASTNode(node);

						parents.push(node);

					} 
					else if ($CountLevel::level > $list::lastLevel) {
						UnorderedListNode unorderedListNode = new UnorderedListNode(top);

						UnorderedListItemNode node = new UnorderedListItemNode($CountLevel::level, unorderedListNode, $elem.items);
						unorderedListNode.addChildASTNode(node);

						top.addChildASTNode(unorderedListNode);

						parents.push(node);

					} 
					else if ($CountLevel::level < $list::lastLevel) {
						ItemNode in = parents.peek();

						while (in.getLevel() > $CountLevel::level) {
							in = parents.pop();
							--$list::lastLevel;
						}

						top = in;

						baseParentableNode = top.getBaseParentableNode();

						UnorderedListItemNode node = new UnorderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);

						if (baseParentableNode instanceof OrderedListItemNode) {
							buildAndComposeListNode(baseParentableNode, node, false);
						} 
						else if (baseParentableNode instanceof OrderedListNode) {
							baseParentableNode = ((OrderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, false);
						}
						else if (baseParentableNode instanceof UnorderedListNode && top instanceof OrderedListItemNode) {
							baseParentableNode = ((UnorderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, false);
						} 
						else {
							baseParentableNode.addChildASTNode(node);
						}

						parents.push(node);

					} 
					else {
						baseParentableNode = top.getBaseParentableNode();

						UnorderedListItemNode node = new UnorderedListItemNode($CountLevel::level, baseParentableNode, $elem.items);

						if (baseParentableNode instanceof OrderedListItemNode) {
							buildAndComposeListNode(baseParentableNode, node, false);
						} 
						else if (baseParentableNode instanceof OrderedListNode ) {
							baseParentableNode = ((OrderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, false);
						} 
						else if (baseParentableNode instanceof UnorderedListNode && top instanceof OrderedListItemNode) {
						 	baseParentableNode = ((UnorderedListNode)baseParentableNode).getBaseParentableNode();

							buildAndComposeListNode(baseParentableNode, node, false);
						} 
						else {
							baseParentableNode.addChildASTNode(node);
						}

						parents.pop();
						parents.push(node);
					}

					$list::lastLevel = $CountLevel::level;
				}
	;
list_elem  returns [CollectionNode  items = null]
	:	( m = list_elem_markup {
			             ++$CountLevel::level;
			             if (!$m.text.equals($CountLevel::currentMarkup)) {
							$CountLevel::groups+= GROUPING_SEPARATOR;
			             }
			             $CountLevel::groups+= $m.text;
			             $CountLevel::currentMarkup = $m.text;
			          } )*  c =list_elemcontent  {$items = $c.items; } list_elemseparator
	;
list_elem_markup
	:	list_ordelem_markup
	|	list_unordelem_markup
	;
list_elemcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( part = list_elemcontentpart  { $items.add($part.node); } onestar )*
	;
list_elemcontentpart returns [ASTNode node = null]
	:	tuf = text_unformattedelement {
				if ($tuf.contents instanceof CollectionNode)
					$node = new UnformattedTextNode($tuf.contents);
				else
					$node = $tuf.contents;
				}
	|	tf = list_formatted_elem { $node = new FormattedTextNode($tf.contents);}
	;
list_formatted_elem returns [CollectionNode contents = new CollectionNode()]
	:	bold_markup  onestar  ( boldContents = list_boldcontentpart  {
						BoldTextNode add = null;
						if ($boldContents.contents instanceof CollectionNode){
						     add = new BoldTextNode($boldContents.contents);
						}
						else {
						    CollectionNode c = new CollectionNode();
						    c.add($boldContents.contents);
						    add = new BoldTextNode(c);
						}
						$contents.add(add);
						}
				onestar )*
		( bold_markup )?
	|	ital_markup    onestar  ( italContents = list_italcontentpart      {
						ItalicTextNode add = null;
						if ($italContents.contents instanceof CollectionNode){
						    add = new ItalicTextNode($italContents.contents);
						}
						else {
						      CollectionNode c = new CollectionNode();
						      c.add($italContents.contents);
						      add = new ItalicTextNode(c);
						}
						$contents.add(add);
						} onestar )*
		( ital_markup )?
	;

list_boldcontentpart returns [ASTNode  contents = null]
scope {
	List elements;
}
@init{
	$list_boldcontentpart::elements = new ArrayList();
}
	:	ital_markup  c = list_bolditalcontent  {$contents = new ItalicTextNode($c.text);} ( ital_markup )?
	|	( t = text_unformattedelement { $list_boldcontentpart::elements.add($t.contents); } )+ {$contents = new CollectionNode($list_boldcontentpart::elements); }
	/*|	would be equivalent ??? ( t = text_unformattedelement { $contents.add($t.contents); } )*/
	;

list_bolditalcontent returns [ASTNode  text = null]
	:	( t = text_unformattedelement { $text = $t.contents; } )+
	;

list_italcontentpart returns [ASTNode  contents  = null]
scope {
	List elements;
}
@init{
	$list_italcontentpart::elements = new ArrayList();
}
	:	bold_markup  c = list_bolditalcontent  { $contents = new BoldTextNode($c.text); } ( bold_markup )?
	|	( t = text_unformattedelement { $list_italcontentpart::elements.add($t.contents); })+ { $contents = new CollectionNode($list_italcontentpart::elements); }
	;

////////////////////////////////   T A B L E   ////////////////////////////////
table returns [TableNode table = new TableNode()]
	:	( tr = table_row {$table.addChildASTNode($tr.row);} )+
	;
table_row  returns [CollectionNode row = new CollectionNode()]
	:	( { input.LA(1) == PIPE && input.LA(2) == PIPE }? 
		table_cell { 
			CollectionNode cn = new CollectionNode();
			cn.add(new UnformattedTextNode(" "));
			TableCellNode space = new TableDataNode(cn);
			$row.add(space);
		}
	|   tc = table_cell { $row.add($tc.cell); } 
	)+  table_rowseparator
	;
table_cell returns [TableCellNode cell = null]
	:	{ input.LA(2) == EQUAL }?  th = table_headercell {$cell = $th.header;}
	|	tc = table_normalcell {$cell = $tc.cell; }
	;
table_headercell returns [TableHeaderNode header = null]
	:	table_headercell_markup  tc = table_cellcontent {$header = new TableHeaderNode($tc.items);}
	;
table_normalcell returns [TableDataNode cell = null]
	:	table_cell_markup  tc = table_cellcontent { $cell = new TableDataNode($tc.items); }
	;
table_cellcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( tcp = table_cellcontentpart  {
			if ($tcp.node != null) {
				$items.add($tcp.node);
			}
		}
		onestar )*
	;
table_cellcontentpart returns [ASTNode node = null]
	:	tf = table_formattedelement {$node=$tf.content;}
	|	tu = table_unformattedelement {$node=$tu.content;}
	;
table_formattedelement returns [ASTNode content = null]
	:	ital_markup   ( tic = table_italcontent { $content = new ItalicTextNode($tic.items); })?  ( ital_markup )?
	|	bold_markup ( tbc= table_boldcontent  {$content = new BoldTextNode($tbc.items);})?  ( bold_markup )?
	;
table_boldcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( tb = table_boldcontentpart  { $items.add($tb.node); } onestar )+
	|	EOF
	;
table_italcontent returns [CollectionNode items = new CollectionNode()]
	:	onestar  ( ti = table_italcontentpart  { $items.add($ti.node); } onestar )+
	|	EOF
	;
table_boldcontentpart returns [ASTNode node = null]
	:	tf = table_formattedcontent {$node = $tf.elements; }
	|	ital_markup  tb = table_bolditalcontent  { $node = new ItalicTextNode($tb.elements);  } ( ital_markup )?
	;
table_italcontentpart returns [ASTNode node = null]
	:	bold_markup  tb = table_bolditalcontent  {$node = new BoldTextNode($tb.elements); } ( bold_markup )?
	|	tf = table_formattedcontent { $node = $tf.elements; }
	;
table_bolditalcontent returns [CollectionNode elements = null]
	:	onestar  ( tfc = table_formattedcontent  { $elements = $tfc.elements; } onestar )?
	|	EOF
	;
table_formattedcontent returns [CollectionNode elements = new CollectionNode()]
	:	( tu = table_unformattedelement { $elements.add($tu.content); } )+
	;
table_unformattedelement returns [ASTNode content = null]
	:	tu = table_unformatted  {$content = new UnformattedTextNode($tu.text);}
	|	ti = table_inlineelement {$content = $ti.element;}
	;
table_inlineelement returns [ASTNode element = null]
	:	l = link {$element = $l.link; }
	|	i =image {$element = $i.image; }
	|	e = extension {$element = $e.node; }
	|	nw =nowiki_inline {$element = $nw.nowiki; }
	;
table_unformatted returns [CollectionNode text = new CollectionNode()]
	:		t = table_unformatted_text { $text.add(new UnformattedTextNode($t.text.toString()));}
		|	(forced_linebreak {$text.add(new ForcedEndOfLineNode());}
		|	e = escaped {$text.add($e.scaped);} )+
	;

table_unformatted_text returns [StringBundler text = new StringBundler()]
	:	( c = ~(	PIPE
			|	ITAL
			|	STAR
			|	LINK_OPEN
			|	IMAGE_OPEN
			|	NOWIKI_OPEN
			|	EXTENSION
			|	FORCED_LINEBREAK
			|	ESCAPE
			|	NEWLINE
			|	EOF )  {$text.append($c.text);} )+
	;
///////////////////////////////   N O W I K I   ///////////////////////////////

nowiki_block returns [NoWikiSectionNode nowikiNode]
	:	nowikiblock_open_markup  contents = nowiki_block_contents {$nowikiNode = new NoWikiSectionNode($contents.text.toString());}
		nowikiblock_close_markup  paragraph_separator
	;

nowikiblock_open_markup
	:	nowiki_open_markup  newline
	;

nowikiblock_close_markup
	:	NOWIKI_BLOCK_CLOSE
	;

nowiki_inline returns [NoWikiSectionNode nowiki = null]
	:	nowiki_open_markup  t = nowiki_inline_contents
		nowiki_close_markup {$nowiki = new NoWikiSectionNode($t.text.toString());}
	;
nowiki_block_contents returns [StringBundler contents = new StringBundler()]
	:(c=~( NOWIKI_BLOCK_CLOSE | EOF ) {$contents.append($c.text);})*
	;

nowiki_inline_contents returns [StringBundler text = new StringBundler()]
	:	(c = ~( NOWIKI_CLOSE| NEWLINE | EOF )  { $text.append($c.text); })*
	;



//////////////////////   H O R I Z O N T A L   R U L E   //////////////////////

horizontalrule returns [ASTNode horizontal = null]
	:	horizontalrule_markup  ( blanks )?  paragraph_separator {$horizontal = new HorizontalNode();}
	;



////////////////////////////////   L I N K   /////////////////////////////////

link returns [LinkNode link = null]
	:	link_open_markup  a =link_address  {$link = $a.link; } (link_description_markup
		d = link_description {
			if ($link == null) { // recover from possible errors
			    $link = new LinkNode();
			}
			$link.setAltCollectionNode($d.node);

			} )?  link_close_markup
	;

link_address returns [LinkNode link =null]
	:	li = link_interwiki_uri  ':'  p = link_interwiki_pagename {
						$li.interwiki.setTitle($p.text.toString());
						$link = $li.interwiki;
					}
	|	lu = link_uri {$link = new LinkNode($lu.text.toString()); }
	;
link_interwiki_uri returns [InterwikiLinkNode interwiki = null]
	:	'C' '2' { $interwiki = new C2InterwikiLinkNode(); }
	|	'D' 'o' 'k' 'u' 'W' 'i' 'k' 'i' { $interwiki = new DokuWikiInterwikiLinkNode(); }
	|	'F' 'l' 'i' 'c' 'k' 'r'  { $interwiki = new FlickrInterwikiLinkNode(); }
	|	'G' 'o' 'o' 'g' 'l' 'e' { $interwiki = new GoogleInterwikiLinkNode(); }
	|	'J' 'S' 'P' 'W' 'i' 'k' 'i' { $interwiki = new JSPWikiInterwikiLinkNode(); }
	|	'M' 'e' 'a' 't' 'b' 'a' 'l' 'l' { $interwiki = new MeatballInterwikiLinkNode(); }
	|	'M' 'e' 'd' 'i' 'a' 'W' 'i' 'k' 'i' { $interwiki = new MediaWikiInterwikiLinkNode(); }
	|	'M' 'o' 'i' 'n' 'M' 'o' 'i' 'n'  { $interwiki = new MoinMoinInterwikiLinkNode(); }
	|	'O' 'd' 'd' 'm' 'u' 's' 'e'  { $interwiki = new OddmuseInterwikiLinkNode(); }
	|	'O' 'h' 'a' 'n' 'a' { $interwiki = new OhanaInterwikiLinkNode(); }
	|	'P' 'm' 'W' 'i' 'k' 'i'  { $interwiki = new PmWikiInterwikiLinkNode(); }
	|	'P' 'u' 'k' 'i' 'W' 'i' 'k' 'i'  { $interwiki = new PukiWikiInterwikiLinkNode(); }
	|	'P' 'u' 'r' 'p' 'l' 'e' 'W' 'i' 'k' 'i' { $interwiki = new PurpleWikiInterwikiLinkNode(); }
	|	'R' 'a' 'd' 'e' 'o' 'x' { $interwiki = new RadeoxInterwikiLinkNode(); }
	|	'S' 'n' 'i' 'p' 'S' 'n' 'a' 'p' { $interwiki = new SnipSnapInterwikiLinkNode(); }
	|	'T' 'i' 'd' 'd' 'l' 'y' 'W' 'i' 'k' 'i' { $interwiki = new TiddlyWikiInterwikiLinkNode(); }
	|	'T' 'W' 'i' 'k' 'i' { $interwiki = new TWikiInterwikiLinkNode(); }
	|	'U' 's' 'e' 'm' 'o' 'd' { $interwiki = new UsemodInterwikiLinkNode(); }
	|	'W' 'i' 'k' 'i' 'p' 'e' 'd' 'i' 'a' { $interwiki = new WikipediaInterwikiLinkNode(); }
	|	'X' 'W' 'i' 'k' 'i' { $interwiki = new XWikiInterwikiLinkNode(); }
	;
link_interwiki_pagename returns [StringBundler text = new StringBundler()]
	:	( c = ~( PIPE | LINK_CLOSE | NEWLINE | EOF ) { $text.append($c.text); } ) +
	;
link_description returns [CollectionNode node = new CollectionNode()]
	:	( l = link_descriptionpart {
					// Recover code: some bad syntax could include null elements in the collection
					if ($l.text != null) {
						$node.add($l.text);
					}
				}
		| i = image {$node.add($i.image);})+
	;
link_descriptionpart returns [ASTNode text = null]
scope{
	CollectionNode element;
}
@init{
	$link_descriptionpart::element = new CollectionNode();
}
	:	bold_markup  onestar ( lb = link_bold_descriptionpart  {$link_descriptionpart::element.add($lb.text);} onestar )+  {$text = new BoldTextNode($link_descriptionpart::element);}
		bold_markup
	|	ital_markup  onestar  ( li = link_ital_descriptionpart {$link_descriptionpart::element.add($li.text);}  onestar )+ {$text = new ItalicTextNode($link_descriptionpart::element);}
		ital_markup
	|	onestar  ( t = link_descriptiontext  onestar {$link_descriptionpart::element.add($t.text);})+ {$text = new UnformattedTextNode($link_descriptionpart::element);}
	;
link_bold_descriptionpart returns [ASTNode text = null]
	:	ital_markup  t = link_boldital_description {$text = new ItalicTextNode($t.text);}  ital_markup
	|	ld = link_descriptiontext {$text =$ld.text;}
	;
link_ital_descriptionpart returns [ASTNode text = null]
	:	bold_markup  td = link_boldital_description  bold_markup {$text = new BoldTextNode($td.text);}
	|	t = link_descriptiontext {$text = $t.text; }
	;
link_boldital_description returns [CollectionNode text = new CollectionNode()]
	:	onestar  ( t = link_descriptiontext  onestar {
					for (ASTNode item:$t.text.getASTNodes()) {
						$text.add(item);
					}
				})+
	;
link_descriptiontext returns [CollectionNode text = new CollectionNode()]
	:		t = link_descriptiontext_simple { $text.add(new UnformattedTextNode($t.text.toString()));}
		|	( forced_linebreak {$text.add(new ForcedEndOfLineNode());}
		|	e = escaped {$text.add($e.scaped);} )+
	;
link_descriptiontext_simple returns [StringBundler text = new StringBundler()]
	:	( c = ~(LINK_CLOSE
			|	ITAL
			|	STAR
			|	LINK_OPEN
			|	IMAGE_OPEN
			|	NOWIKI_OPEN
			|	EXTENSION
			|	FORCED_LINEBREAK
			|	ESCAPE
			|	NEWLINE
			|	EOF ) { $text.append($c.text); } )+
	;
link_uri returns [StringBundler text = new StringBundler()]
	:	( c = ~( PIPE | LINK_CLOSE | NEWLINE | EOF ) {$text.append($c.text); } )+
	;



////////////////////////////////   I M A G E   ////////////////////////////////

image returns [ImageNode image = new ImageNode()]
	:	image_open_markup uri = image_uri {$image.setLink($uri.link.toString());}  ( alt =image_alternative {$image.setAltCollectionNode($alt.alternative);} )?
		image_close_markup
	;
image_uri returns [StringBundler link = new StringBundler()]
	:	(c = ~( PIPE | IMAGE_CLOSE | NEWLINE | EOF ) {$link.append($c.text); })+
	;
image_alternative returns [CollectionNode alternative = new CollectionNode()]
	:	image_alternative_markup  ( p = image_alternativepart {$alternative.add($p.item); } )+
	;
image_alternativepart returns [ASTNode item = null]
scope{
    CollectionNode elements;
}
@init{
   $image_alternativepart::elements = new CollectionNode();
}
	:	bold_markup  onestar  ( t1 = image_bold_alternativepart  {$image_alternativepart::elements.add($t1.text);} onestar )+
		bold_markup {$item = new BoldTextNode($image_alternativepart::elements);}
	|	ital_markup  onestar  (  t2 = image_ital_alternativepart  {$image_alternativepart::elements.add($t2.text);} onestar )+
		ital_markup {$item = new ItalicTextNode($image_alternativepart::elements);}
	|	onestar  ( t3=image_alternativetext  {
					for (ASTNode n: $t3.items.getASTNodes()) {
					   $image_alternativepart::elements.add(n);
					 }
				              } onestar )+ {$item =new UnformattedTextNode($image_alternativepart::elements);}
	;
image_bold_alternativepart returns [ASTNode text = null]
scope{
    CollectionNode elements;
}
@init{
   $image_bold_alternativepart::elements = new CollectionNode();
}
	:	ital_markup  t = link_boldital_description  {$text = new ItalicTextNode($t.text); } ital_markup
	|	onestar  ( i = image_alternativetext  onestar{
					for (ASTNode item:$i.items.getASTNodes()) {
					    $image_ital_alternativepart::elements.add(item);
					}
					} )+ {$text = new UnformattedTextNode($image_bold_alternativepart::elements);}
	;

image_ital_alternativepart returns [ASTNode text = null]
scope{
    CollectionNode elements;
}
@init{
   $image_ital_alternativepart::elements = new CollectionNode();
}
	:	bold_markup  t = link_boldital_description  {$text = new BoldTextNode($t.text); } bold_markup
	|	onestar  (i =  image_alternativetext  onestar {
					for (ASTNode item:$i.items.getASTNodes()) {
					    $image_ital_alternativepart::elements.add(item);
					}
					} )+ {$text = new UnformattedTextNode($image_ital_alternativepart::elements);}
	;
image_boldital_alternative returns [CollectionNode text = new CollectionNode()]
	:	onestar  ( i = image_alternativetext  onestar {
					for (ASTNode item:$i.items.getASTNodes()) {
					    $text.add(item);
					}
					})+
	;
image_alternativetext returns [CollectionNode items = new CollectionNode()]
	:	contents = image_alternative_simple_text {$items.add(new UnformattedTextNode($contents.text.toString())); }
	|	(forced_linebreak {$items.add(new ForcedEndOfLineNode());})+
	;

image_alternative_simple_text returns [StringBundler text = new StringBundler()]
	:
	( c = ~( 	IMAGE_CLOSE
			|	ITAL
			|	STAR
			|	LINK_OPEN
			|	IMAGE_OPEN
			|	NOWIKI_OPEN
			|	EXTENSION
			|	FORCED_LINEBREAK
			|	NEWLINE
			|	EOF ) {$text.append($c.text); } ) +
	;

/////////////////////////////  E X T E N S I O N  /////////////////////////////

extension returns [ASTNode node = null]
	:	extension_markup  extension_handler  blanks  extension_statement
		extension_markup
	;

extension_handler
	:	(~( EXTENSION  |  BLANKS  |  ESCAPE  |  NEWLINE  |  EOF ) | escaped )+
	;

extension_statement
	:	(~( EXTENSION  |  ESCAPE  |  EOF ) | escaped )*
	;


/////////////////////////////  TABLE OF CONTENTS EXTENSION  /////////////////////////////

table_of_contents returns [TableOfContentsNode tableOfContents = new TableOfContentsNode()]
	:
		(
			'<>'
			|
			'<>'
		)
	;


table_of_contents_title_text returns [StringBundler text = new StringBundler()]
	:	( c = ~(LINK_OPEN | IMAGE_OPEN | NOWIKI_OPEN |EQUAL | ESCAPE | NEWLINE | EOF | '>>' )  {$text.append($c.text);} )+
	;

onestar
	:	( { input.LA(2) != STAR }?  ( STAR )?)
	|
	;
escaped returns [ScapedNode scaped = new ScapedNode()]
	:	ESCAPE   c =. { $scaped.setContent($c.text) ; }
		// '.' in a parser rule means arbitrary token, not character
	;
paragraph_separator
	:	( newline )+
	|	EOF
	;
whitespaces
	:	( blanks | newline )+
	;
blanks
	:	BLANKS
	;
text_lineseparator
	:	newline  ( blanks )?
	|	EOF
	;
newline
	:	NEWLINE
	;
bold_markup
	:	STAR  STAR
	;
ital_markup
	:	ITAL
	;
heading_markup
	:	EQUAL
	;
list_ordelem_markup
	:	POUND
	;
list_unordelem_markup
	:	STAR
	;
list_elemseparator
	:	newline  ( blanks )?
	|	EOF
	;
end_of_list
	:	newline
	|	EOF
	;
table_cell_markup
	:	PIPE
	;
table_headercell_markup
	:	PIPE  EQUAL
	;
table_rowseparator
	:	newline
	|	EOF
	;
nowiki_open_markup
	:	NOWIKI_OPEN
	;
nowiki_close_markup
	:	NOWIKI_CLOSE
	;
horizontalrule_markup
	:	DASH  DASH  DASH  DASH
	;
link_open_markup
	:	LINK_OPEN
	;
link_close_markup
	:	LINK_CLOSE
	;
link_description_markup
	:	PIPE
	;
image_open_markup
	:	IMAGE_OPEN
	;
image_close_markup
	:	IMAGE_CLOSE
	;
image_alternative_markup
	:	PIPE
	;
extension_markup
	:	EXTENSION
	;
forced_linebreak
	:	FORCED_LINEBREAK
	;



///////////////////////////////////////////////////////////////////////////////
///////////////////////// S C A N N E R    R U L E S //////////////////////////
///////////////////////////////////////////////////////////////////////////////

ESCAPE					: '~';
NOWIKI_BLOCK_CLOSE		: NEWLINE  '}}}';
NEWLINE					: ( CR )?  LF
						| CR;
fragment CR				: '\r';
fragment LF				: '\n';

BLANKS					: ( SPACE | TABULATOR )+;
fragment SPACE			: ' ';
fragment TABULATOR		: '\t';

BRACE_CLOSE				: NEWLINE '}';
COLON_SLASH				: ':'  '/';
ITAL					: '//';
NOWIKI_OPEN				: '{{{';
NOWIKI_CLOSE			: '}}}';
LINK_OPEN				: '[[';
LINK_CLOSE				: ']]';
IMAGE_OPEN				: '{{';
IMAGE_CLOSE				: '}}';
FORCED_LINEBREAK		: '\\\\';
EQUAL					: '=';
PIPE					: '|';
POUND					: '#';
DASH					: '-';
STAR					: '*';
SLASH					: '/';
EXTENSION				: '@@';

INSIGNIFICANT_CHAR		: .;




© 2015 - 2025 Weber Informatics LLC | Privacy Policy