001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.transformer.cfml.script;
020
021import lucee.commons.lang.ExceptionUtil;
022import lucee.commons.lang.ParserString;
023import lucee.commons.lang.StringUtil;
024import lucee.transformer.bytecode.expression.Expression;
025import lucee.transformer.bytecode.literal.LitBoolean;
026import lucee.transformer.bytecode.literal.LitString;
027import lucee.transformer.bytecode.statement.tag.Attribute;
028
029public class DocCommentTransformer {
030        
031        public synchronized DocComment transform(String str){
032                try{
033                        DocComment dc = new DocComment();
034                        str=str.trim();
035                        if(str.startsWith("/**")) str=str.substring(3);
036                        if(str.endsWith("*/")) str=str.substring(0,str.length()-2);
037                        ParserString ps=new ParserString(str);
038                        transform(dc,ps);
039                        dc.getHint();// TODO do different -> make sure internal structure is valid
040                        return dc;
041                }
042                catch(Throwable t){
043                        ExceptionUtil.rethrowIfNecessary(t);
044                        return null;
045                }
046        }
047
048        private void transform(DocComment dc, ParserString ps) {
049                while(ps.isValidIndex()){
050                        asterix(ps);
051                        ps.removeSpace();
052                        // param
053                        if(ps.forwardIfCurrent('@')){
054                                dc.addParam(param(ps));
055                        }
056                        // hint
057                        else {
058                                while(ps.isValidIndex() && ps.getCurrent()!='\n'){
059                                        dc.addHint(ps.getCurrent());
060                                        ps.next();
061                                }
062                                dc.addHint('\n');
063                        }
064                        ps.removeSpace();
065                }
066        }
067
068        private Attribute param(ParserString ps) {
069                String name=paramName(ps);
070                if(name==null) return new Attribute(true,"@",LitBoolean.TRUE,"boolean");
071                
072                // white space
073                while(ps.isValidIndex() && ps.isCurrentWhiteSpace()){
074                        if(ps.getCurrent()=='\n')
075                                return new Attribute(true,name,LitBoolean.TRUE,"boolean");
076                        ps.next();
077                }
078                Expression value = paramValue(ps);
079                return new Attribute(true,name, value,value instanceof LitBoolean?"boolean":"string");
080        }
081
082        private String paramName(ParserString ps) {
083                StringBuilder sb=new StringBuilder();
084                while(ps.isValidIndex() && !ps.isCurrentWhiteSpace()){
085                        sb.append(ps.getCurrent());
086                        ps.next();
087                }
088                if(sb.length()==0) return null;
089                return sb.toString();
090        }
091
092        private Expression paramValue(ParserString ps) {
093                StringBuilder sb=new StringBuilder();
094                while(ps.isValidIndex() && ps.getCurrent()!='\n'){
095                        sb.append(ps.getCurrent());
096                        ps.next();
097                }
098                if(sb.length()==0) return LitBoolean.TRUE;
099                return LitString.toExprString(unwrap(sb.toString()));
100        }
101
102        public static String unwrap(String str) {
103                str = str.trim();
104                if(StringUtil.startsWith(str, '"') && StringUtil.endsWith(str, '"'))
105                        str=str.substring(1,str.length()-1);
106                if(StringUtil.startsWith(str, '\'') && StringUtil.endsWith(str, '\''))
107                        str=str.substring(1,str.length()-1);
108                return str;
109        }
110
111        private void asterix(ParserString ps) {
112                do {
113                        ps.removeSpace();
114                }while(ps.forwardIfCurrent('*'));
115                
116        }
117        
118}