GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / web / org / codehaus / groovy / grails / web / pages / Scan.java
blob2c3586066ec92b2045906976c4042a4c54e17413
1 /*
2 * Copyright 2004-2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.codehaus.groovy.grails.web.pages;
18 /**
19 * NOTE: Based on work done by on the GSP standalone project (https://gsp.dev.java.net/)
21 * Lexer for GroovyPagesServlet.
23 * @author Troy Heninger
24 * @author Graeme Rocher
26 * Date: Jan 10, 2004
29 class Scan implements Tokens {
30 private String text;
31 private int end1, begin1, end2, begin2, state = HTML, len, level;
32 private boolean str1, str2;
33 private String lastNamespace;
34 private int exprBracketCount = 0;
36 Scan(String text) {
37 Strip strip = new Strip(text);
38 strip.strip(0);
39 this.text = strip.toString();
40 len = this.text.length();
41 this.lastNamespace = null;
42 } // Scan()
44 private int found(int newState, int skip) {
45 begin2 = begin1;
46 end2 = --end1;
47 begin1 = end1 += skip;
48 int lastState = state;
49 state = newState;
50 return lastState;
51 } // found()
53 private int foundStartOrEndTag(int newState, int skip, String namespace) {
54 begin2 = begin1;
55 end2 = --end1;
56 begin1 = end1 += skip;
57 int lastState = state;
58 state = newState;
59 lastNamespace = namespace;
60 return lastState;
61 } // found()
63 String getToken() {
64 return text.substring(begin2, end2);
65 } // getToken()
67 String getNamespace() {
68 return lastNamespace;
71 int nextToken() {
72 for (;;) {
73 int left = len - end1;
74 if (left == 0) {
75 end1++; // in order to include the last letter
76 return found(EOF, 0);
78 char c = text.charAt(end1++);
79 char c1 = left > 1 ? text.charAt(end1) : 0;
80 char c2 = left > 2 ? text.charAt(end1 + 1) : 0;
81 char c3 = left > 3 ? text.charAt(end1 + 2) : 0;
83 StringBuffer chars = new StringBuffer()
84 .append(c)
85 .append(c1)
86 .append(c2);
87 String startTag = chars.toString();
89 String endTag = chars
90 .append(c3)
91 .toString();
93 if (str1) {
94 if (c == '\\') end1++;
95 else if (c == '\'') str1 = false;
96 continue;
97 } else if (str2) {
98 if (c == '\\') end1++;
99 else if (c == '"') str2 = false;
100 continue;
101 } else if (level > 0 && (c == ')' || c == '}' || c == ']')) {
102 level--;
103 continue;
106 switch (state) {
107 case HTML:
108 if (c == '<' && left > 3) {
109 if (c1 == '%') {
110 if (c2 == '=') {
111 return found(JEXPR, 3);
112 } else if (c2 == '@') {
113 return found(JDIRECT, 3);
114 } else if (c2 == '!') {
115 return found(JDECLAR, 3);
116 } else if (c2 == '-' && left > 3 && text.charAt(end1 + 2) == '-') {
117 if (skipJComment()) continue;
119 return found(JSCRIPT, 2);
121 else {
122 boolean bStartTag = true;
123 int fromIndex = end1; // we are expecting a start tag.
124 if (c1 == '/') {
125 bStartTag = false;
126 fromIndex = end1 + 1; // well it should be an end tag.
129 int foundColonIdx = text.indexOf(":", fromIndex);
130 if (foundColonIdx > -1) {
131 String tagNameSpace = text.substring(fromIndex,foundColonIdx);
132 if (tagNameSpace.matches("^\\p{Alpha}\\w*$")) {
133 if (bStartTag) {
134 return foundStartOrEndTag(GSTART_TAG,tagNameSpace.length() + 2,tagNameSpace);
136 else {
137 return foundStartOrEndTag(GEND_TAG,tagNameSpace.length() + 3,tagNameSpace);
142 } else if (c == '$' && c1 == '{') {
143 return found(GEXPR, 2);
144 } else if (c == '%' && c1 == '{') {
145 if (c2 == '-' && left > 3 && text.charAt(end1 + 2) == '-') {
146 if (skipGComment()) continue;
148 return found(GSCRIPT, 2);
149 } else if (c == '!' && c1 == '{') {
150 return found(GDECLAR, 2);
151 } else if (c == '@' && c1 == '{') {
152 return found(GDIRECT, 2);
154 break;
155 case JEXPR:
156 case JSCRIPT:
157 case JDIRECT:
158 case JDECLAR:
159 if (c == '%' && c1 == '>') {
160 return found(HTML, 2);
162 break;
163 case GSTART_TAG:
164 if(c == '$' && c1 == '{') {
165 return found(GTAG_EXPR, 2);
167 if(c == '>') {
168 return found(HTML,1);
170 else if(c == '/' && c1 == '>') {
171 return found(GEND_TAG,1);
173 break;
174 case GEND_TAG:
175 if(c == '>') {
176 return found(HTML,1);
178 break;
179 case GTAG_EXPR:
180 if(c == '{') exprBracketCount++;
181 else if(c == '}') {
182 if(exprBracketCount>0) {
183 exprBracketCount--;
185 else {
186 return found(GSTART_TAG,1);
189 break;
190 case GEXPR:
191 case GDIRECT:
192 if (c == '}' && !str1 && !str2 && level == 0) {
193 return found(HTML, 1);
195 break;
196 case GSCRIPT:
197 if (c == '}' && c1 == '%' && !str1 && !str2 && level == 0) {
198 return found(HTML, 2);
200 break;
201 case GDECLAR:
202 if (c == '}' && (c1 == '!' || c1 == '%') && !str1 && !str2 && level == 0) {
203 return found(HTML, 2);
205 break;
208 } // nextToken()
210 private boolean skipComment(char c3, char c4) {
211 int ix = end1 + 3;
212 for (int ixz = len - 4; ; ix++) {
213 if (ix >= ixz) return false;
214 if (text.charAt(ix) == '-' && text.charAt(ix + 1) == '-' && text.charAt(ix + 2) == c3
215 && text.charAt(ix + 3) == c4) break;
217 text = text.substring(0, --end1) + text.substring(ix + 4);
218 len = text.length();
219 return true;
220 } // skipComment()
222 private boolean skipGComment() {
223 return skipComment('}', '%');
224 } // skipGComment()
226 private boolean skipJComment() {
227 return skipComment('%', '>');
228 } // skipJComment()
230 void reset() {
231 end1= begin1 = end2 = begin2 = level = 0;
232 state = HTML;
233 lastNamespace = null;
234 } // reset()
236 } // Scan