001    package railo.transformer.bytecode.statement.tag;
002    
003    import java.util.HashMap;
004    import java.util.Iterator;
005    import java.util.List;
006    import java.util.Map;
007    
008    import railo.commons.lang.StringUtil;
009    import railo.runtime.type.util.ComponentUtil;
010    import railo.transformer.bytecode.Body;
011    import railo.transformer.bytecode.BodyBase;
012    import railo.transformer.bytecode.BytecodeContext;
013    import railo.transformer.bytecode.BytecodeException;
014    import railo.transformer.bytecode.Literal;
015    import railo.transformer.bytecode.Page;
016    import railo.transformer.bytecode.Position;
017    import railo.transformer.bytecode.Statement;
018    import railo.transformer.bytecode.expression.ExprString;
019    import railo.transformer.bytecode.expression.Expression;
020    import railo.transformer.bytecode.literal.LitBoolean;
021    import railo.transformer.bytecode.literal.LitLong;
022    import railo.transformer.bytecode.literal.LitString;
023    import railo.transformer.bytecode.statement.FlowControlFinal;
024    import railo.transformer.bytecode.statement.IFunction;
025    import railo.transformer.bytecode.statement.PrintOut;
026    import railo.transformer.bytecode.statement.udf.Function;
027    import railo.transformer.bytecode.statement.udf.FunctionImpl;
028     
029    public final class TagFunction extends TagBase implements IFunction {
030    
031            private static final ExprString ANY = LitString.toExprString("any");
032    
033            private static final Expression PUBLIC = LitString.toExprString("public");
034    
035            private static final Expression EMPTY = LitString.toExprString("");
036            
037            public TagFunction(Position start,Position end) {
038                    super(start,end);
039                    
040            }
041            
042            /**
043             * @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int)
044             */
045            public void writeOut(BytecodeContext bc, int type) throws BytecodeException {
046            //ExpressionUtil.visitLine(bc, getStartLine());
047            _writeOut(bc,type);
048            //ExpressionUtil.visitLine(bc, getEndLine());
049            }
050            
051            /**
052             * @see railo.transformer.bytecode.statement.tag.TagBase#_writeOut(railo.transformer.bytecode.BytecodeContext)
053             */
054            public void _writeOut(BytecodeContext bc) throws BytecodeException {
055                    _writeOut(bc,Function.PAGE_TYPE_REGULAR);
056            }
057    
058            public void _writeOut(BytecodeContext bc, int type) throws BytecodeException {
059                    Body functionBody = new BodyBase();
060                    Function func = createFunction(bc.getPage(),functionBody);
061                    func.setParent(getParent());
062    
063                    List<Statement> statements = getBody().getStatements();
064                    Statement stat;
065                    Tag tag;
066                    
067                    // supress WS between cffunction and the last cfargument
068                    Tag last=null;
069                    if(bc.getSupressWSbeforeArg()){
070                            // check if there is a cfargument at all
071                            Iterator<Statement> it = statements.iterator();
072                            while (it.hasNext()) {
073                                    stat = it.next();
074                                    if (stat instanceof Tag) {
075                                            tag = (Tag) stat;
076                                            if (tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Argument")) {
077                                                    last=tag;
078                                            }
079                                    }
080                            }
081                            
082                            // check if there are only literal WS printouts
083                            if(last!=null) {
084                                    it = statements.iterator();
085                                    while (it.hasNext()) {
086                                            stat = it.next();
087                                            if(stat==last) break;
088                                            
089                                            if(stat instanceof PrintOut){
090                                                    PrintOut po=(PrintOut) stat;
091                                                    Expression expr = po.getExpr();
092                                                    if(!(expr instanceof LitString) || !StringUtil.isWhiteSpace(((LitString)expr).getString())) {
093                                                            last=null;
094                                                            break;
095                                                    }
096                                            }
097                                    }
098                            }
099                    }
100                    
101                    
102                    
103                    Iterator<Statement> it = statements.iterator();
104                    boolean beforeLastArgument=last!=null;
105                    while (it.hasNext()) {
106                            stat = it.next();
107                            if(beforeLastArgument) {
108                                    if(stat==last) {
109                                            beforeLastArgument=false;
110                                    }
111                                    else if(stat instanceof PrintOut){
112                                            PrintOut po=(PrintOut) stat;
113                                            Expression expr = po.getExpr();
114                                            if(expr instanceof LitString) {
115                                                    LitString ls=(LitString) expr;
116                                                    if(StringUtil.isWhiteSpace(ls.getString())) continue;
117                                            }
118                                    }
119                                    
120                            }
121                            if (stat instanceof Tag) {
122                                    tag = (Tag) stat;
123                                    if (tag.getTagLibTag().getTagClassName().equals(
124                                                    "railo.runtime.tag.Argument")) {
125                                            addArgument(func, tag);
126                                            continue;
127                                    }
128                            }
129                            functionBody.addStatement(stat);
130                    }
131                    func._writeOut(bc,type);
132    
133            }
134    
135            private void addArgument(Function func, Tag tag) {
136                    Attribute attr;
137                    // name
138                    Expression name = tag.removeAttribute("name").getValue();
139                    
140                    // type
141                    attr = tag.removeAttribute("type");
142                    Expression type = (attr == null) ? ANY : attr.getValue();
143    
144                    // required
145                    attr = tag.removeAttribute("required");
146                    Expression required = (attr == null) ? LitBoolean.FALSE : attr
147                                    .getValue();
148    
149                    // default
150                    attr = tag.removeAttribute("default");
151                    Expression defaultValue = (attr == null) ? null : attr.getValue();
152                    
153                    // passby
154                    attr = tag.removeAttribute("passby");
155                    LitBoolean passByReference = LitBoolean.TRUE;
156                    if(attr!=null) {
157                            // i can cast irt to LitString because he evulator check this before
158                             String str = ((LitString)attr.getValue()).getString();
159                             if(str.trim().equalsIgnoreCase("value"))
160                                     passByReference=LitBoolean.FALSE;
161                    }
162                    
163                    
164                    // displayname
165                    attr = tag.removeAttribute("displayname");
166                    Expression displayName = (attr == null) ? EMPTY : attr.getValue();
167    
168                    // hint
169                    attr = tag.removeAttribute("hint");
170                    if (attr == null)
171                            attr = tag.removeAttribute("description");
172                    
173                    Expression hint;
174                    if(attr == null)hint=EMPTY;
175                    else hint=attr.getValue();
176                    
177                    func.addArgument(name, type, required, defaultValue, passByReference,displayName, hint,tag.getAttributes());
178    
179            }
180    
181            private Function createFunction(Page page, Body body) throws BytecodeException {
182                    Attribute attr;
183    
184                    // name
185                    Expression name = removeAttribute("name").getValue();
186                    /*if(name instanceof LitString) {
187                            ((LitString)name).upperCase();
188                    }*/
189                    // return
190                    attr = removeAttribute("returntype");
191                    // if(attr==null) attr = getAttribute("return");
192                    // if(attr==null) attr = getAttribute("type");
193                    Expression returnType = (attr == null) ? ANY : attr.getValue();
194    
195                    // output
196                    attr = removeAttribute("output");
197                    Expression output = (attr == null) ? LitBoolean.TRUE : attr.getValue();
198                    
199                    // bufferOutput
200                    attr = removeAttribute("bufferoutput");
201                    Expression bufferOutput = (attr == null) ? null : attr.getValue();
202    
203                    // modifier
204                    boolean _abstract=false,_final=false;
205                    attr = removeAttribute("modifier");
206                    if(attr!=null) {
207                            Expression val = attr.getValue();
208                            if(val instanceof Literal) {
209                                    Literal l=(Literal) val;
210                                    String str = StringUtil.emptyIfNull(l.getString()).trim();
211                                    if("abstract".equalsIgnoreCase(str))_abstract=true;
212                                    else if("final".equalsIgnoreCase(str))_final=true;
213                            }
214                    }
215    
216                    // access
217                    attr = removeAttribute("access");
218                    Expression access = (attr == null) ? PUBLIC : attr.getValue();
219    
220                    // dspLabel
221                    attr = removeAttribute("displayname");
222                    Expression displayname = (attr == null) ? EMPTY : attr.getValue();
223    
224                    // hint
225                    attr = removeAttribute("hint");
226                    Expression hint = (attr == null) ? EMPTY : attr.getValue();
227    
228                    // description
229                    attr = removeAttribute("description");
230                    Expression description = (attr == null) ? EMPTY : attr.getValue();
231    
232                    // returnformat
233                    attr = removeAttribute("returnformat");
234                    Expression returnFormat = (attr == null) ? null : attr.getValue();
235    
236                    // secureJson
237                    attr = removeAttribute("securejson");
238                    Expression secureJson = (attr == null) ? null : attr.getValue();
239    
240                    // verifyClient
241                    attr = removeAttribute("verifyclient");
242                    Expression verifyClient = (attr == null) ? null : attr.getValue();
243    
244                    // localMode
245                    attr = removeAttribute("localmode");
246                    Expression localMode = (attr == null) ? null : attr.getValue();
247                    
248                    
249                    
250                    // cachedWithin
251                    long cachedWithin=0;
252                    attr = removeAttribute("cachedwithin");
253                    if(attr!=null) {
254                            Expression val = attr.getValue();
255                            if(val instanceof LitLong)
256                                    cachedWithin=((LitLong)val).getLongValue();
257                    }
258                    
259                    String strAccess = ((LitString)access).getString();
260                    int acc = ComponentUtil.toIntAccess(strAccess,-1);
261                    if(acc==-1)
262                            throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getStart());
263            
264                    Function func = new FunctionImpl(page,name, returnType,returnFormat, output, bufferOutput, acc, displayname,description,
265                                    hint,secureJson,verifyClient,localMode,cachedWithin,_abstract,_final, body, getStart(),getEnd());
266                     
267                    
268                    
269                    
270    //               %**%
271                    Map attrs = getAttributes();
272                    Iterator it = attrs.entrySet().iterator();
273                    HashMap<String,Attribute> metadatas=new HashMap<String,Attribute>();
274                    while(it.hasNext()){
275                            attr=(Attribute) ((Map.Entry)it.next()).getValue();
276                            metadatas.put(attr.getName(),attr);
277                    }
278                    func.setMetaData(metadatas);
279                    return func;
280            }
281            
282            @Override
283            public FlowControlFinal getFlowControlFinal() {
284                    return null;
285            }
286    
287    }