grammar JSP; | |
/* | |
* Copyright (c) 2010 Mia-Software and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v2.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v20.html | |
* | |
* Contributors: | |
* | |
* Nicolas Guyomar (Mia-Software) - initial API and implementation | |
*/ | |
/* | |
Limitation: | |
------------------------------- | |
1. Non closed tag will be generated opened/closed without any children | |
2. Closed tags alone will be dealt with as Text element | |
3. Closed tags cannot have attribute | |
4. Attribute without any simple nor double quote can only contain one Digit, or onID, one tag, one jsp_element | |
5. Tag name cannot start with a special caracter, like <!tagName> | |
6. Attribute's values contained between double quote cannot contain other double quote as text | |
*/ | |
options { | |
language = Java; | |
} | |
@lexer::header { | |
/** | |
* Copyright (c) 2010 Mia-Software and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v2.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v20.html | |
* | |
* Contributors: | |
* | |
* Nicolas Guyomar (Mia-Software) - initial API and implementation | |
* | |
*/ | |
package org.eclipse.modisco.jee.jsp.discoverer.parser; | |
import org.eclipse.modisco.infra.common.core.logging.MoDiscoLogger; | |
import org.eclipse.modisco.jee.jsp.discoverer.JspActivator; | |
} | |
@header { | |
/** | |
* Copyright (c) 2010 Mia-Software and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v2.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v20.html | |
* | |
* Contributors: | |
* | |
* Nicolas Guyomar (Mia-Software) - initial API and implementation | |
* | |
*/ | |
package org.eclipse.modisco.jee.jsp.discoverer.parser; | |
import org.eclipse.modisco.jee.jsp.*; | |
import org.eclipse.modisco.jee.jsp.impl.*; | |
import java.util.HashMap; | |
import org.eclipse.modisco.xml.*; | |
import org.eclipse.modisco.xml.emf.MoDiscoXMLFactory; | |
import org.eclipse.modisco.infra.common.core.logging.MoDiscoLogger; | |
import org.eclipse.modisco.jee.jsp.discoverer.JspActivator; | |
} | |
@lexer::members { | |
//This method redirect error messages from ANTLR to MoDisco Logger | |
@Override | |
public void displayRecognitionError(String[] tokenNames, | |
RecognitionException e) { | |
String hdr = getErrorHeader(e); | |
String msg = getErrorMessage(e, tokenNames); | |
MoDiscoLogger.logWarning("Lexer error in "+this.filePath+" "+hdr+" "+msg, JspActivator.getDefault()); | |
} | |
private String filePath; | |
public JSPLexer(CharStream input, String path) { | |
super(input); | |
this.filePath = path; | |
} | |
} | |
@members { | |
//This method redirect error messages from ANTLR to MoDisco Logger | |
@Override | |
public void displayRecognitionError(String[] tokenNames, | |
RecognitionException e) { | |
String hdr = getErrorHeader(e); | |
String msg = getErrorMessage(e, tokenNames); | |
MoDiscoLogger.logWarning("Parser error in "+this.page.getOriginalFilePath()+" "+hdr+" "+msg, JspActivator.getDefault()); | |
} | |
private JspFactory factory = new JspFactoryImpl(); | |
private MoDiscoXMLFactory xmlFactory = MoDiscoXMLFactory.eINSTANCE; | |
public String space = ""; | |
private ArrayList<Node> closedTagList = new ArrayList<Node>(); | |
private ArrayList<Node> tagList = new ArrayList<Node>(); | |
private ArrayList<Node> javaScriptParentList = new ArrayList<Node>(); | |
public Page page = factory.createPage(); | |
/** | |
* Method to factorize some code in the JavaScript rule | |
*/ | |
public void createJavascriptText(Element tag, String text){ | |
if(!text.equalsIgnoreCase("")){ | |
Text textElt = this.xmlFactory.createText(); | |
textElt.setName(text); | |
tag.getChildren().add(textElt); | |
} | |
} | |
/** | |
* Generic method which link a child to his parent | |
* @param parentPage The page itself | |
* @param parentTag The parent tag | |
* @param child The child | |
*/ | |
public void setParent( Element parentTag, Node child) { | |
if(parentTag!=null && child !=null) | |
{ | |
parentTag.getChildren().add(child); | |
} | |
else if(child!=null){ | |
//All tag are by default child of the page | |
this.page.getOwnedElements().add(child); | |
//We put all the tags in the list | |
tagList.add(child); | |
} | |
} | |
public void createAttributeText(Element att, String textContent){ | |
if(!textContent.equalsIgnoreCase("")&&att!=null){ | |
Text text = this.xmlFactory.createText(); | |
text.setName(textContent); | |
att.getChildren().add(text); | |
} | |
} | |
/** | |
* This method recreates the tree hierarchy of the file | |
* Given the name of a closing tag, it look in the list of all the | |
* encountered tags to find the opening one. Every tag between those two | |
* is considered to be a son of the opening one | |
* @param closeTagName the name of the closing tag encountered | |
*/ | |
public void resolveChild(String closeTagName) | |
{ | |
Element tag = null; | |
//We first need to check that this closed tag is a real one, meaning | |
//if it does have a openTag | |
int k = tagList.size()-1; | |
boolean isARealClosedTag = false; | |
while(k>=0) | |
{ | |
if(tagList.get(k)!=null){ | |
if(tagList.get(k) instanceof Element){ | |
tag = (Element) tagList.get(k); | |
//If we find the related open tag | |
if(tag.getName().equalsIgnoreCase(closeTagName)&& !closedTagList.contains(tag)){ | |
isARealClosedTag = true; | |
closedTagList.add(tag); | |
break; | |
} | |
} | |
} | |
k--; | |
} | |
int endIndex = tagList.size()-1; | |
int numberOfChildren = endIndex-k; | |
if(!tagList.isEmpty() && isARealClosedTag){ | |
for(int j=0;j<numberOfChildren;j++){ | |
tag.getChildren().add(tagList.get(k+1)); | |
tagList.remove(k+1); | |
} | |
} | |
//We are facing a closed element out of nowhere, but we still need to process it | |
else{ | |
Text elt =this.xmlFactory.createText(); | |
elt.setName("</"+closeTagName+">"); | |
this.page.getOwnedElements().add(elt); | |
} | |
} | |
/** | |
* This method concatenate every token contained within the beginning of the tag | |
* and the token matching the given token ID | |
* It is very usefull to retriveve content for JSP Scriplet for instance | |
* @param tokenID the ID of the closing token in the token list | |
* @param tag the tag we need the content for | |
*/ | |
public void getTagContent(int tokenID, Element tag){ | |
String text = ""; | |
loop1: | |
do { | |
//Avoid index out of bound exception | |
if(input.mark()== input.size()) | |
{ | |
break loop1; | |
} | |
if ( (input.LA(1)==tokenID) ) { | |
break loop1; | |
} | |
else{ | |
text+= space+input.get(input.mark()).getText(); | |
matchAny(input); | |
} | |
} while (true); | |
Text textElmt = xmlFactory.createText(); | |
while(text.startsWith("\n") ||text.startsWith(" ") ){ | |
text = text.substring(1); | |
} | |
textElmt.setName(text); | |
setParent(tag, textElmt); | |
tag.setName(""); | |
} | |
public JSPStdAction createJSPStdAction(Element parent,String name){ | |
JSPStdAction tag = this.factory.createJSPStdAction(); | |
setParent(parent, tag); | |
tag.setName(name); | |
return tag; | |
} | |
} | |
/** | |
A page is composed with tags (html, javascript) and some jsp element | |
*/ | |
page[String originalFilePath, String fileName] | |
: | |
{ | |
this.page.setOriginalFilePath(originalFilePath); | |
this.page.setName(fileName); | |
} | |
( | |
xmlDecl | |
|docType | |
|jsp_element[null] | |
|tag[null] | |
|endtag | |
|comment[null] | |
|text[null] | |
|cData[null] | |
)* | |
; | |
//XML Declaration on top of file | |
fragment xmlDecl : t = XMLDECL {this.page.setXmlDeclaration(t.getText());} ; | |
//DTD Declaration | |
fragment docType : t=DOCTYPE {this.page.setDoctype(t.getText());} ; | |
CDATA | |
: '<![CDATA[' (options {greedy=false;} : .)* ']]>' | |
; | |
fragment cData [Element parent] returns[CDATA tag] | |
: | |
cData2s=CDATA | |
{ | |
tag = this.xmlFactory.createCDATA(); | |
tag.setName(cData2s.getText()); | |
setParent(parent, tag); | |
} | |
; | |
fragment jsp_element[Element parent] returns[Element tag] | |
: | |
jsp_scriplet[parent] {tag=$jsp_scriplet.tag;} | |
|jsp_expression[parent] {tag=$jsp_expression.tag;} | |
|jsp_declaration[parent] {tag=$jsp_declaration.tag;} | |
|jsp_action[ parent] {tag=$jsp_action.tag;} | |
|jsp_directive[parent] {tag=$jsp_directive.tag;} | |
; | |
fragment endtag returns[Element tag] | |
: | |
// | |
'</' WS? id1=ID (WS? ':' WS? id2=ID)? WS?'>' | |
{ | |
String endTagName = id1.getText()+ (id2!=null?":"+id2.getText():"") ; //\$NON-NLS-1\$ | |
resolveChild(endTagName); | |
} | |
; | |
fragment tag[Element parent] returns[Element tag] | |
: | |
( | |
{ | |
Boolean isJavascript = false; | |
} | |
//HTML | |
'<' WS? id1=ID | |
{ | |
isJavascript = id1.getText().equalsIgnoreCase("script");//\$NON-NLS-1\$ | |
if(isJavascript) | |
{ | |
tag = this.factory.createJavaScript(); | |
String tmp = id1.getText() ; | |
// tag.setName(tmp); | |
setParent(parent,tag); | |
//We Should concatenate every token we found till we meet </script> | |
//But we do not want to declare "</script>" as a token because then it creates some problems | |
String text = "";//\$NON-NLS-1\$ | |
Boolean tagHeader = true; | |
loop1: | |
do { | |
if(input.LT(1).getText()!=null && input.LT(2).getText()!=null && input.LT(3).getText()!=null){ | |
//End of script tag | |
if (input.LT(1).getText().equalsIgnoreCase("</")//\$NON-NLS-1\$ | |
&& input.LT(2).getText().equalsIgnoreCase("script")//\$NON-NLS-1\$ | |
&& input.LT(3).getText().equalsIgnoreCase(">") ) //\$NON-NLS-1\$ | |
{ | |
//We need to consume the 3 next token for '</' 'script' '>' | |
input.consume(); | |
input.consume(); | |
input.consume(); | |
break loop1; | |
} | |
//end of the tag script element | |
else if(input.LT(1).getText().equalsIgnoreCase(">") && tagHeader)//\$NON-NLS-1\$ | |
{ | |
//We need to retrieve the content of the tag, eg : attributes | |
tag.setName(text); | |
//We do not want to change the title | |
tagHeader = false; | |
matchAny(input); | |
text=""; | |
} | |
else | |
{ | |
/**This is the part where occured the JSP element detection | |
* This part is static, meaning if some token's name is changed in the grammar rule | |
* it has to be manually changed here | |
**/ | |
switch ( input.LA(1) ) { | |
//SCRIPLET CASE | |
case JSPTAGOPEN: | |
case OPENSCRIPLET: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
jsp_scriplet(tag); | |
} | |
break; | |
//JSP EXPRESSION CASE | |
case JSPOPENEXPR: | |
case OPENEXPR: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
jsp_expression(tag); | |
} | |
break; | |
//JSP DECLARATION CASE | |
case JSPOPENDECL: | |
case OPENDECL: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
jsp_declaration(tag); | |
} | |
break; | |
//JSP STANDART ACTION CASE | |
case JSPUSEBEAN: | |
case JSPSET: | |
case JSPGET: | |
case JSPOPENINC: | |
case JSPOPENFWD: | |
case JSPOPENPLUG: | |
case JSPOPENROOT: | |
case JSPOPENTEXT: | |
case JSPOPENATTR: | |
case JSPOPENBODY: | |
case JSPOPENINVOKE: | |
case JSPOPENDOBODY: | |
case JSPOPENOUTPUT: | |
case JSPELEMENTOP: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
jsp_action(tag); | |
} | |
break; | |
//JSP ACTION CASE | |
//The constant has to match to token id of the '<' caracter | |
case 67: | |
{ | |
if(input.LA(2) == ID && input.LA(3)==DDOT && input.LA(4)== ID){ | |
createJavascriptText(tag,text); text = ""; | |
jsp_action(tag); | |
} | |
else{ | |
text+=space+input.get(input.mark()).getText(); | |
matchAny(input); | |
} | |
} | |
break; | |
//JSP DIRECTIVE CASE | |
case JSPOPENDIR: | |
case OPENDIRECT: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
jsp_directive(tag); | |
} | |
break; | |
//JSP COMMENT CASE | |
case JSP_COMMENT: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
comment(tag); | |
} | |
break; | |
//Case of a closing tag | |
case 21: | |
{ | |
createJavascriptText(tag,text); text = ""; | |
Boolean parentFound = false; | |
String closingTagName=input.LT(2).getText()+ | |
input.LT(3).getText()+input.LT(4).getText(); | |
Node parentNode = null; | |
ArrayList<Node> toBeAdded = new ArrayList<Node>(); | |
for(Node node : tag.getChildren()){ | |
if(!parentFound){ | |
if(node.getName().equalsIgnoreCase(closingTagName)){ | |
parentFound = true; | |
parentNode = node; | |
} | |
}else | |
{ | |
toBeAdded.add(node); | |
} | |
} | |
for(Node child:toBeAdded){ | |
((Element)parentNode).getChildren().add(child); | |
} | |
input.consume(); | |
input.consume(); | |
input.consume(); | |
input.consume(); | |
input.consume(); | |
} | |
break; | |
default: | |
text+=space+input.get(input.mark()).getText(); | |
matchAny(input); | |
} | |
} | |
}else{ | |
//This case would appear if there is a problem in the file formation, or the | |
// abscence of the </script> tag | |
MoDiscoLogger.logInfo("The </script> was not detected ", JspActivator.getDefault()); | |
break loop1; | |
} | |
} while (true); | |
createJavascriptText(tag,text); text = ""; | |
return tag; | |
} | |
else | |
{ | |
tag = xmlFactory.createElement(); | |
} | |
String tmp = id1.getText() ; | |
tag.setName(tmp); | |
setParent(parent,tag); | |
} | |
( | |
// endtag | |
// | | |
attribute[tag] | WS | |
| | |
jsp=jsp_element[tag] | |
{ | |
//We need to know when a JSP element is contained in the tag | |
//or if it is just a casual children | |
if(jsp instanceof JSPScript){ | |
((JSPScript)jsp).setIsTagFragment(true); | |
} | |
else if(jsp instanceof JSPAction ){ | |
((JSPAction)jsp).setIsTagFragment(true); | |
} | |
else if(jsp instanceof JSPComment){ | |
((JSPComment)jsp).setIsTagFragment(true); | |
} | |
} | |
)* | |
('>' |'/>') | |
) | |
; | |
fragment jsp_scriplet[Element parent] returns[JSPScriptlet tag] | |
: | |
//Version 1.0 | |
( | |
'<%' //START | |
{ | |
tag = this.factory.createJSPScriptlet(); | |
setParent(parent, tag); | |
getTagContent(JSPTAGCLOSE,tag); | |
} | |
'%>' //END | |
) | |
| | |
//Version 2.0 | |
( | |
'<jsp:scriptlet>' //START | |
{ | |
tag = this.factory.createJSPScriptlet(); | |
setParent( parent, tag); | |
getTagContent(CLOSESCRIPTLET,tag); | |
} | |
'</jsp:scriptlet>' //END | |
) | |
; | |
fragment jsp_declaration[Element parent] returns[Element tag] | |
: | |
//JSPDeclaration Section | |
//Version 1.0 | |
( | |
'<%!' //START | |
{ | |
tag = this.factory.createJSPDeclaration(); | |
setParent(parent, tag); | |
getTagContent(JSPTAGCLOSE,tag); | |
} | |
'%>' //END | |
) | |
| | |
( | |
'<jsp:declaration>' //START | |
{ | |
tag = this.factory.createJSPDeclaration(); | |
setParent( parent, tag); | |
getTagContent(CLOSEDECL,tag); | |
} | |
'</jsp:declaration>' //END | |
) | |
; | |
fragment jsp_directive[Element parent] returns[Element tag] | |
: | |
//JSPDirective Section | |
'<%@' WS? //START | |
id1=ID | |
{ | |
if(id1.getText().equalsIgnoreCase("taglib")){//\$NON-NLS-1\$ | |
tag = this.factory.createJSPTagLib(); | |
}else{ | |
tag = this.factory.createJSPDirective(); | |
} | |
tag.setName(id1.getText()); | |
setParent( parent, tag); | |
} | |
(attribute[tag]|WS)* | |
'%>' //END | |
| | |
{ | |
tag = this.factory.createJSPDirective(); | |
setParent( parent, tag); | |
} | |
'<jsp:directive.' WS? id2=ID (attribute[tag]|WS)* '/>' | |
{ | |
tag.setName(id2.getText()); | |
} | |
; | |
fragment jsp_expression[Element parent] returns[JSPExpression tag] | |
: | |
//Version 1.0 | |
( | |
'<%=' //START | |
{ | |
tag = this.factory.createJSPExpression(); | |
setParent( parent, tag); | |
getTagContent(JSPTAGCLOSE,tag); | |
} | |
'%>' //END | |
) | |
| | |
//Version 2.0 | |
( | |
'<jsp:expression>' //START | |
{ | |
tag = this.factory.createJSPExpression(); | |
setParent( parent, tag); | |
getTagContent(CLOSEEXPR,tag); | |
} | |
'</jsp:expression>' //END | |
) | |
; | |
fragment jsp_action[Element parent] returns[JSPAction tag] | |
: | |
( | |
'<' WS? id1=ID WS? ':' WS? id2=ID | |
{ | |
tag = this.factory.createJSPAction(); | |
tag.setName(id1.getText()+":"+id2.getText()); | |
setParent( parent, tag); | |
} | |
( | |
attribute[tag] | |
| WS | |
| | |
jsp=jsp_element[tag] | |
{ | |
//We need to know when a JSP element is contained in the tag | |
//or if it is just a casual children | |
if(jsp instanceof JSPScript){ | |
((JSPScript)jsp).setIsTagFragment(true); | |
} | |
else if(jsp instanceof JSPAction ){ | |
((JSPAction)jsp).setIsTagFragment(true); | |
} | |
else if(jsp instanceof JSPComment){ | |
((JSPComment)jsp).setIsTagFragment(true); | |
} | |
} | |
)* | |
('>' |'/>') | |
) | |
| | |
jsp_standard_action[parent]{tag=$jsp_standard_action.tag;} | |
; | |
//###################################################################################### | |
//####################### START OF STANDARD ACTIONS ############################## | |
//###################################################################################### | |
fragment jsp_standard_action[Element parent]returns[JSPStdAction tag] | |
: | |
jsp_include[parent] {tag=$jsp_include.tag;}//JSP INCLUDE | |
|jsp_plugin[parent] {tag=$jsp_plugin.tag;}//JSP PLUGIN | |
|jsp_getProperty[parent] {tag=$jsp_getProperty.tag;}//JSP GETPROPERTY | |
|jsp_setProperty[parent] {tag=$jsp_setProperty.tag;}//JSP SETPROPERTY | |
|jsp_useBean[parent] {tag=$jsp_useBean.tag;}//JSP USE BEAN | |
|jsp_forward[parent] {tag=$jsp_forward.tag;}//JSP FORWARD | |
|jsp_dobody[parent] {tag=$jsp_dobody.tag;}//JSP DOBODY | |
|jsp_output[parent] {tag=$jsp_output.tag;}//JSP OUTPUT | |
|jsp_invoke[parent] {tag=$jsp_invoke.tag;}//JSP INVOKE | |
|jsp_body[parent] {tag=$jsp_body.tag;}//JSP BODY | |
|jsp_attribute[parent] {tag=$jsp_attribute.tag;}//JSP ATTRIBUTE | |
|jsp_text[parent] {tag=$jsp_text.tag;}//JSP TEXT | |
|jsp_root[parent] {tag=$jsp_root.tag;}//JSP ROOT | |
|jsp_eltStdAct[parent] {tag=$jsp_eltStdAct.tag;} | |
; | |
/* | |
*/ | |
fragment jsp_eltStdAct[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:element");//\$NON-NLS-1\$ | |
} | |
'<jsp:element' (attribute[tag]|WS)* | |
( // Left Factoring | |
'/>' | |
| | |
'>' | |
(jsp_element[tag]|comment[tag]| WS)* | |
'</jsp:element>' | |
) | |
; | |
/* | |
<jsp:root | |
xmlns:jsp="http://.../JSP/Page" | |
[ xmlns:taglibPrefix="URI" ]+ ... | |
version="1.2 | 2.0"> | |
JSP Page | |
</jsp:root> | |
*/ | |
fragment jsp_root[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:root");//\$NON-NLS-1\$ | |
} | |
'<jsp:root' (attribute[tag]|WS)* '>' | |
(comment[tag]|jsp_element[tag]|WS)* | |
'</jsp:root>' | |
; | |
fragment jsp_include [Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:include");//\$NON-NLS-1\$ | |
} | |
'<jsp:include' (attribute[tag]|WS)* | |
( | |
'>' | |
(jsp_param[tag] | comment[tag]|WS)* | |
'</jsp:include>' | |
| | |
'/>' | |
) | |
; | |
fragment jsp_forward[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:forward");//\$NON-NLS-1\$ | |
} | |
'<jsp:forward' (attribute[tag]|WS)* '>' | |
(jsp_param[tag] | comment[tag]|WS)* | |
'</jsp:forward>' | |
; | |
/* | |
<jsp:plugin type="applet" height="100%" width="100%" | |
codebase="/applets" | |
code="MyApplet" > | |
<jsp:params> | |
<jsp:param name="enableDebug" value="true" /> | |
</jsp:params> | |
<jsp:fallback> | |
Your browser does not support this | |
</jsp:fallback> | |
</jsp:plugin> | |
*/ | |
fragment jsp_plugin[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:plugin");//\$NON-NLS-1\$ | |
} | |
'<jsp:plugin' (attribute[tag]|WS)* '>' | |
(jsp_param[tag] | jsp_fallback[tag] | comment[tag]|WS)* | |
'</jsp:plugin>' | |
; | |
/*<jsp:fallback> | |
Your browser does not support this | |
</jsp:fallback> */ | |
fragment jsp_fallback[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:fallback");//\$NON-NLS-1\$ | |
} | |
'<jsp:fallback>' | |
{getTagContent(JSPCLOSEFALL,tag);} | |
'</jsp:fallback>' | |
{ | |
tag.setName("jsp:fallback"); | |
} | |
; | |
//<jsp:getProperty name="beanName" property="lastModification" /> | |
fragment jsp_getProperty[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:getProperty");//\$NON-NLS-1\$ | |
} | |
'<jsp:getProperty' (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
/*<jsp:setProperty name="beanName" | |
*property="lastModification" value="<%= new Date()%>" | |
/>*/ | |
fragment jsp_setProperty[Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:setProperty");//\$NON-NLS-1\$ | |
} | |
'<jsp:setProperty' (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
// <jsp:useBean id="beanName" class="package.Bean" scope="request" /> | |
fragment jsp_useBean [Element parent] returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:useBean");//\$NON-NLS-1\$ | |
} | |
('<jsp:useBean') (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
//<jsp:param name="enableDebug" value="true" /> | |
fragment jsp_param[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:param");//\$NON-NLS-1\$ | |
} | |
'<jsp:param' (attribute[tag]|comment[tag]|WS)* '/>' | |
| | |
{ | |
tag = createJSPStdAction(parent,"jsp:params");//\$NON-NLS-1\$ | |
} | |
'<jsp:params>' (jsp_param[tag]|comment[tag]|WS)* '</jsp:params>' | |
; | |
/* | |
<jsp:doBody ({var="scopedAttributeName" | | |
varReader="scopedAttributeName" } | |
[scope="page | request | session | application" ] />) | /> | |
*/ | |
fragment jsp_dobody[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:doBody");//\$NON-NLS-1\$ | |
} | |
'<jsp:doBody' (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
/* | |
<jsp:output ( omit-xml-declaration="yes|no|true|false" ) | |
{ doctypeDecl } /> | |
doctypeDecl ::= ( doctype-root-element="rootElement" | |
doctype-public="PubidLiteral" | |
doctype-system="SystemLiteral" ) | |
| ( doctype-root-element="rootElement" | |
doctype-system="SystemLiteral" ) | |
*/ | |
fragment jsp_output[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:output");//\$NON-NLS-1\$ | |
} | |
'<jsp:output' (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
/* | |
<jsp:invoke fragment="fragmentName" | |
({var="scopedAttributeName" | | |
varReader="scopedAttributeName"} | |
[scope="page | request | session | application" ] />) | |
| /> | |
*/ | |
fragment jsp_invoke[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:invoke");//\$NON-NLS-1\$ | |
} | |
'<jsp:invoke' (attribute[tag]|comment[tag]|WS)* '/>' | |
; | |
/* | |
<jsp:body>any elements or text</jsp:body> | |
*/ | |
fragment jsp_body[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:body");//\$NON-NLS-1\$ | |
} | |
'<jsp:body>' (text[tag]|jsp_element[tag])* '</jsp:body>' | |
{ | |
tag.setName("jsp:body"); | |
} | |
; | |
//<jsp:attribute name="attributeName" [ trim= "true | false" ] /> | |
fragment jsp_attribute[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:attribute");//\$NON-NLS-1\$ | |
} | |
( | |
'<jsp:attribute' (attribute[tag]|comment[tag]|WS)* | |
( | |
'/>' | |
| | |
'>' | |
(jsp_element[tag]|comment[tag]|WS)* | |
'</jsp:attribute>' | |
) | |
) | |
; | |
/* | |
<jsp:text> | |
template data | |
</jsp:text> | |
*/ | |
fragment jsp_text[Element parent]returns [JSPStdAction tag] | |
: | |
{ | |
tag = createJSPStdAction(parent,"jsp:text");//\$NON-NLS-1\$ | |
} | |
'<jsp:text>' {getTagContent(JSPCLOSETEXT,tag);} '</jsp:text>' | |
{ | |
tag.setName("jsp:text"); //\$NON-NLS-1\$ | |
} | |
; | |
//###################################################################################### | |
//####################### END OF STANDARD ACTIONS ############################### | |
//###################################################################################### | |
fragment comment[Element parent] | |
: | |
jsp_comment[parent]|line_comment[parent] | |
; | |
fragment jsp_comment[Element parent] returns[JSPComment tag] | |
: | |
t=JSP_COMMENT | |
{ | |
tag = this.factory.createJSPComment(); | |
setParent(parent, tag); | |
tag.setName(t.getText()); | |
} | |
; | |
fragment line_comment[Element parent] returns[Comment tag] | |
: | |
t=LINE_COMMENT | |
{ | |
tag = xmlFactory.createComment(); | |
setParent(parent, tag); | |
tag.setName(t.getText()); | |
} | |
; | |
fragment text[Element parent] returns[Text text] | |
: | |
{ | |
String content = ""; | |
} | |
( id=ID {content+= id.getText();} | |
| dig=Digit {content+= dig.getText();} | |
| speChar=SpecialCharacter { content+= speChar.getText();} | |
| DQUOTE { content+= "\"";} | |
| SQUOTE { content+= "\'";} | |
| DDOT { content+= ":";} | |
| EQUAL { content+= "=";} | |
| ws=WS {if(!content.equalsIgnoreCase("")){ content+=ws.getText();} }//We do not want to get all the blank lines in the | |
//model, it is useless | |
//the '"' and ''' characters should not be included in the | |
//SpecialCharacter Lexer Rule | |
) | |
{ | |
loop21: | |
do { | |
if(input.mark()== input.size()) | |
{ | |
break loop21; | |
} | |
switch ( input.LA(1) ) { | |
//The first case is the token number for character '<' | |
case 67: | |
case EOF: | |
case XMLDECL: | |
case DOCTYPE: | |
case JSPTAGOPEN: | |
case OPENSCRIPLET: | |
case JSPOPENEXPR: | |
case OPENEXPR: | |
case JSPOPENDECL: | |
case OPENDECL: | |
case JSPOPENINC: | |
case JSPOPENPLUG: | |
case JSPGET: | |
case JSPSET: | |
case JSPUSEBEAN: | |
case JSPOPENFWD: | |
case JSPOPENDOBODY: | |
case JSPOPENOUTPUT: | |
case JSPOPENINVOKE: | |
case JSPOPENBODY: | |
case JSPOPENATTR: | |
case JSPOPENTEXT: | |
case JSPOPENROOT: | |
case JSPELEMENTOP: | |
case JSPOPENDIR: | |
case OPENDIRECT: | |
case OPENCLOSE: | |
case JSP_COMMENT: | |
case LINE_COMMENT: | |
case JSPCLOSEBODY: | |
case CDATA: | |
{ | |
break loop21; | |
} | |
} | |
content+= space+input.get(input.mark()).getText(); //\$NON-NLS-1\$ | |
matchAny(input); | |
} while (true); | |
//We need to remove the \n character which appears at the beginning of | |
//each new line | |
while(content.startsWith("\n")){ | |
content = content.substring(1); | |
} | |
if(!content.equalsIgnoreCase("") && !content.equalsIgnoreCase("\n")){ | |
Text textElmt = xmlFactory.createText(); | |
textElmt.setName(content); | |
setParent(parent, textElmt); | |
} | |
} | |
; | |
fragment attribute[Element parent] | |
: | |
{ | |
String value=""; | |
Attribute xmlAttr = this.xmlFactory.createAttribute(); | |
ComposedAttribute compAttr = null; | |
} | |
/* An attribute usually seems like : | |
name = "value" | |
name = 'value' | |
name = value | |
but also | |
JSP = "JSP" | |
JSP = 'JSP' | |
JSP = JSP | |
*/ | |
//NAME | |
name=ID (WS? ':' WS? name2=ID)? | |
{ | |
String attributeName = name.getText(); | |
if(name2!=null){ | |
attributeName+=":"+name2.getText(); | |
} | |
xmlAttr.setName(attributeName); | |
} | |
//VALUE | |
(WS?'='WS? | |
( | |
( | |
('"' | |
( | |
{ | |
xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
tag[compAttr] | |
| | |
{ | |
xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
jsp_element[compAttr] | |
|t=SpecialCharacter {value+=t.getText();} | |
|SQUOTE {value+="'";} // Only possible when contained with double quote | |
|EQUAL {value+="=";} //For Meta Tag with 'charset=iso-8859-1' for instance | |
|DDOT {value+=":";} //For URL for instance | |
|';' {value+=";";} | |
|ws=WS {value+=ws.getText();} | |
|digit1=Digit {value+=space+digit1.getText();} | |
|id1=ID {value+=space+$id1.text;} | |
)* | |
('>'{value+=">";})? | |
('<'{value+="<";})? | |
{ if(xmlAttr==null){ | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
else{xmlAttr.setValue(value);}; | |
} | |
('"')+ //We may have several quote by mistake | |
) | |
) | |
(';'{ if(xmlAttr==null) { | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,";");value=""; | |
} | |
else{xmlAttr.setValue(xmlAttr.getValue()+";");}; | |
})? | |
| | |
('\'' | |
( | |
{ | |
xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
tag[compAttr] | |
| | |
{ | |
xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
jsp_element[compAttr] | |
|digit2=Digit {value+=space+digit2.getText();} | |
|id1=ID {value+=space+$id1.text;} | |
|t=SpecialCharacter {value+=t.getText();} | |
|EQUAL {value+="=";} //For Meta Tag with 'charset=iso-8859-1' for instance | |
|DDOT {value+=":";} //For URL for instance | |
|';' {value+=";";} | |
|DQUOTE {value+="\"";} | |
|ws=WS {value+=ws.getText();} | |
)* | |
('>'{value+=">";})? | |
('<'{value+="<";})? | |
{ if(xmlAttr==null){ | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value=""; | |
} | |
else{xmlAttr.setValue(value);}; | |
} | |
'\'') | |
| | |
( | |
id1=ID {value+=space+$id1.text;} | |
|digit2=Digit {value+=space+digit2.getText();} | |
|{xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value="";}jsp_element[compAttr] | |
|{xmlAttr=null; | |
if(compAttr==null){compAttr = this.factory.createComposedAttribute(); } | |
createAttributeText(compAttr,value);value="";} tag[compAttr] | |
) | |
{if(xmlAttr!=null){xmlAttr.setValue(value);}} | |
) | |
)? //We could have just an ID ... without EQUAL character | |
{ | |
if(xmlAttr!=null){ | |
setParent(parent,xmlAttr); | |
} | |
else{ | |
compAttr.setName(attributeName); | |
setParent(parent,compAttr); | |
} | |
} | |
; | |
LINE_COMMENT | |
: | |
'<!--' (options {greedy=false;} : .).* '-->' | |
; | |
JSP_COMMENT | |
: | |
'<%--' (options {greedy=false;} : .).* '--%>' | |
; | |
XMLDECL | |
: | |
'<?'('x'|'X')('m'|'M')('l'|'L') (options {greedy=false;} : .)* '?>' | |
; | |
DOCTYPE | |
: | |
'<!'('D'|'d')('O'|'o')('C'|'c')('T'|'t')('Y'|'y')('P'|'p')('E'|'e')(options {greedy=false;} : .)* '>' | |
; | |
fragment INTERNAL_DTD : '[' (options {greedy=false;} : .)* ']' ; | |
ID | |
: ( LETTER | '_' | '&' | '#') | |
( options {greedy=true;} : LETTER | IDDigit | '.' | '-' | '_' | '@' | '°')* | |
; | |
fragment LETTER | |
: '\u0024' |'\u00A0' | |
|'\u0041'..'\u005a' | |
|'\u0061'..'\u007a' | |
|'\u00c0'..'\u00d6' | |
|'\u00d8'..'\u00f6' | |
|'\u00f8'..'\u00ff' | |
|'\u0100'..'\u1fff' | |
|'\u3040'..'\u318f' | |
|'\u3300'..'\u337f' | |
|'\u3400'..'\u3d2d' | |
|'\u4e00'..'\u9fff' | |
|'\uf900'..'\ufaff' | |
|'\u20AC' //Symbole euro | |
|'\u2032'..'\u2037' //Guillemets simple/double/triple version italique | |
|'\u2018'..'\u201F' // voir : http://fr.wikipedia.org/wiki/Guillemets | |
; | |
fragment IDDigit | |
: | |
'\u0030'..'\u0039' | |
; | |
SpecialCharacter | |
: | |
'\u00A0'..'\u00FF' | |
|'\u2400'..'\u377F'// Unicode table : http://fr.wikipedia.org/wiki/ISO_8859 | |
|'{' | |
|'}' | |
|'|' | |
|'!' | |
|'#' | |
|'$' | |
|'&' | |
|'(' | |
|')' | |
|'*' | |
|'+' | |
|',' | |
|'-' | |
|'--' | |
|'.' | |
|'\/' | |
|';' | |
|'?' | |
|'[' | |
|']' | |
|'`' | |
|'%' | |
|'@' | |
|'\\' | |
|'//' | |
|'^' | |
; | |
SQUOTE : '\''; | |
DQUOTE : '"'; | |
DDOT : ':'; | |
EQUAL : '='; | |
WS | |
: | |
//(' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;} | |
(' ' |'\n')+ | |
; | |
//White Space, we may have to parse them in order to make sure we | |
//have no loss of content in the model | |
//If you remove the channel = HIDDEN you'll have to deal yourself with the WS | |
WS2 | |
: | |
( '\r' | '\f' | '\t' )+ {$channel = HIDDEN;} | |
; | |
//A digit is composed with digit from 0 to 9, and may contain | |
//'.' , '%' or ',' //for float or percentage management | |
Digit | |
: | |
//minus for digit, '#' for html color | |
(('-'|'#'|'+')?)('\u0030'..'\u0039')('\u0030'..'\u0039' | '%' | ',' | '.')* | |
; | |
OPENCLOSE : '</'; // typically </br> | |
//1.0 JSP Element | |
JSPTAGOPEN : '<%' ; | |
JSPTAGCLOSE : '%>' ; | |
JSPOPENEXPR : '<%='; | |
JSPOPENDECL : '<%!'; | |
JSPOPENDIR : '<%@'; | |
JSPCLOSEACT : '/>'; | |
//STANDARD ACTION | |
JSPUSEBEAN : '<jsp:useBean'; | |
JSPSET : '<jsp:setProperty'; | |
JSPGET : '<jsp:getProperty'; | |
JSPOPENINC : '<jsp:include'; | |
JSPCLOSEINC : '</jsp:include>'; | |
JSPOPENFWD : '<jsp:forward'; | |
JSPCLOSEFWD : '</jsp:forward>'; | |
JSPOPENPLUG : '<jsp:plugin'; | |
JSPCLOSEPLUG: '</jsp:plugin>'; | |
JSPOPENFALL : '<jsp:fallback>'; | |
JSPCLOSEFALL: '</jsp:fallback>'; | |
JSPOPENPARA : '<jsp:param'; | |
JSPOPENPARAS: '<jsp:params>'; | |
JSPCLOSEPARAS:'</jsp:params>'; | |
JSPOPENROOT : '<jsp:root'; | |
JSPCLOSEROOT: '</jsp:root>'; | |
JSPOPENTEXT : '<jsp:text>'; | |
JSPCLOSETEXT: '</jsp:text>'; | |
JSPCLOSEATTR: '</jsp:attribute>'; | |
JSPOPENATTR : '<jsp:attribute'; | |
JSPOPENBODY : '<jsp:body>'; | |
JSPCLOSEBODY: '</jsp:body>'; | |
JSPOPENINVOKE: '<jsp:invoke'; | |
JSPOPENDOBODY: '<jsp:doBody'; | |
JSPOPENOUTPUT: '<jsp:output'; | |
JSPELEMENTOP : '<jsp:element'; | |
//2.0 JSP Element | |
OPENSCRIPLET: '<jsp:scriptlet>'; | |
CLOSESCRIPTLET: '</jsp:scriptlet>'; | |
OPENEXPR : '<jsp:expression>'; | |
CLOSEEXPR : '</jsp:expression>'; | |
OPENDECL : '<jsp:declaration>' ; | |
CLOSEDECL : '</jsp:declaration>'; | |
OPENDIRECT : '<jsp:directive.'; | |
//Comment | |
OPENJSPCMT : '<%--'; | |
CLOSEJSPCMT : '--%>'; | |
OPENXMLCMT : '<!--'; | |
CLOSEXMLCMT : '-->'; | |
XMLDECLOPEN : '<?xml'; | |
//LINK : '<LINK'; | |