package railo.transformer.bytecode.statement.tag;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import railo.commons.lang.StringUtil;
import railo.runtime.type.util.ComponentUtil;
import railo.transformer.bytecode.Body;
import railo.transformer.bytecode.BodyBase;
import railo.transformer.bytecode.BytecodeContext;
import railo.transformer.bytecode.BytecodeException;
import railo.transformer.bytecode.Literal;
import railo.transformer.bytecode.Page;
import railo.transformer.bytecode.Position;
import railo.transformer.bytecode.Statement;
import railo.transformer.bytecode.expression.ExprString;
import railo.transformer.bytecode.expression.Expression;
import railo.transformer.bytecode.literal.LitBoolean;
import railo.transformer.bytecode.literal.LitLong;
import railo.transformer.bytecode.literal.LitString;
import railo.transformer.bytecode.statement.FlowControlFinal;
import railo.transformer.bytecode.statement.IFunction;
import railo.transformer.bytecode.statement.PrintOut;
import railo.transformer.bytecode.statement.udf.Function;
import railo.transformer.bytecode.statement.udf.FunctionImpl;
public final class TagFunction extends TagBase implements IFunction {
private static final ExprString ANY = LitString.toExprString("any");
private static final Expression PUBLIC = LitString.toExprString("public");
private static final Expression EMPTY = LitString.toExprString("");
public TagFunction(Position start,Position end) {
super(start,end);
}
/**
* @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int)
*/
public void writeOut(BytecodeContext bc, int type) throws BytecodeException {
//ExpressionUtil.visitLine(bc, getStartLine());
_writeOut(bc,type);
//ExpressionUtil.visitLine(bc, getEndLine());
}
/**
* @see railo.transformer.bytecode.statement.tag.TagBase#_writeOut(railo.transformer.bytecode.BytecodeContext)
*/
public void _writeOut(BytecodeContext bc) throws BytecodeException {
_writeOut(bc,Function.PAGE_TYPE_REGULAR);
}
public void _writeOut(BytecodeContext bc, int type) throws BytecodeException {
Body functionBody = new BodyBase();
Function func = createFunction(bc.getPage(),functionBody);
func.setParent(getParent());
List<Statement> statements = getBody().getStatements();
Statement stat;
Tag tag;
// supress WS between cffunction and the last cfargument
Tag last=null;
if(bc.getSupressWSbeforeArg()){
// check if there is a cfargument at all
Iterator<Statement> it = statements.iterator();
while (it.hasNext()) {
stat = it.next();
if (stat instanceof Tag) {
tag = (Tag) stat;
if (tag.getTagLibTag().getTagClassName().equals("railo.runtime.tag.Argument")) {
last=tag;
}
}
}
// check if there are only literal WS printouts
if(last!=null) {
it = statements.iterator();
while (it.hasNext()) {
stat = it.next();
if(stat==last) break;
if(stat instanceof PrintOut){
PrintOut po=(PrintOut) stat;
Expression expr = po.getExpr();
if(!(expr instanceof LitString) || !StringUtil.isWhiteSpace(((LitString)expr).getString())) {
last=null;
break;
}
}
}
}
}
Iterator<Statement> it = statements.iterator();
boolean beforeLastArgument=last!=null;
while (it.hasNext()) {
stat = it.next();
if(beforeLastArgument) {
if(stat==last) {
beforeLastArgument=false;
}
else if(stat instanceof PrintOut){
PrintOut po=(PrintOut) stat;
Expression expr = po.getExpr();
if(expr instanceof LitString) {
LitString ls=(LitString) expr;
if(StringUtil.isWhiteSpace(ls.getString())) continue;
}
}
}
if (stat instanceof Tag) {
tag = (Tag) stat;
if (tag.getTagLibTag().getTagClassName().equals(
"railo.runtime.tag.Argument")) {
addArgument(func, tag);
continue;
}
}
functionBody.addStatement(stat);
}
func._writeOut(bc,type);
}
private void addArgument(Function func, Tag tag) {
Attribute attr;
// name
Expression name = tag.removeAttribute("name").getValue();
// type
attr = tag.removeAttribute("type");
Expression type = (attr == null) ? ANY : attr.getValue();
// required
attr = tag.removeAttribute("required");
Expression required = (attr == null) ? LitBoolean.FALSE : attr
.getValue();
// default
attr = tag.removeAttribute("default");
Expression defaultValue = (attr == null) ? null : attr.getValue();
// passby
attr = tag.removeAttribute("passby");
LitBoolean passByReference = LitBoolean.TRUE;
if(attr!=null) {
// i can cast irt to LitString because he evulator check this before
String str = ((LitString)attr.getValue()).getString();
if(str.trim().equalsIgnoreCase("value"))
passByReference=LitBoolean.FALSE;
}
// displayname
attr = tag.removeAttribute("displayname");
Expression displayName = (attr == null) ? EMPTY : attr.getValue();
// hint
attr = tag.removeAttribute("hint");
if (attr == null)
attr = tag.removeAttribute("description");
Expression hint;
if(attr == null)hint=EMPTY;
else hint=attr.getValue();
func.addArgument(name, type, required, defaultValue, passByReference,displayName, hint,tag.getAttributes());
}
private Function createFunction(Page page, Body body) throws BytecodeException {
Attribute attr;
// name
Expression name = removeAttribute("name").getValue();
/*if(name instanceof LitString) {
((LitString)name).upperCase();
}*/
// return
attr = removeAttribute("returntype");
// if(attr==null) attr = getAttribute("return");
// if(attr==null) attr = getAttribute("type");
Expression returnType = (attr == null) ? ANY : attr.getValue();
// output
attr = removeAttribute("output");
Expression output = (attr == null) ? LitBoolean.TRUE : attr.getValue();
// bufferOutput
attr = removeAttribute("bufferoutput");
Expression bufferOutput = (attr == null) ? null : attr.getValue();
// modifier
boolean _abstract=false,_final=false;
attr = removeAttribute("modifier");
if(attr!=null) {
Expression val = attr.getValue();
if(val instanceof Literal) {
Literal l=(Literal) val;
String str = StringUtil.emptyIfNull(l.getString()).trim();
if("abstract".equalsIgnoreCase(str))_abstract=true;
else if("final".equalsIgnoreCase(str))_final=true;
}
}
// access
attr = removeAttribute("access");
Expression access = (attr == null) ? PUBLIC : attr.getValue();
// dspLabel
attr = removeAttribute("displayname");
Expression displayname = (attr == null) ? EMPTY : attr.getValue();
// hint
attr = removeAttribute("hint");
Expression hint = (attr == null) ? EMPTY : attr.getValue();
// description
attr = removeAttribute("description");
Expression description = (attr == null) ? EMPTY : attr.getValue();
// returnformat
attr = removeAttribute("returnformat");
Expression returnFormat = (attr == null) ? null : attr.getValue();
// secureJson
attr = removeAttribute("securejson");
Expression secureJson = (attr == null) ? null : attr.getValue();
// verifyClient
attr = removeAttribute("verifyclient");
Expression verifyClient = (attr == null) ? null : attr.getValue();
// localMode
attr = removeAttribute("localmode");
Expression localMode = (attr == null) ? null : attr.getValue();
// cachedWithin
long cachedWithin=0;
attr = removeAttribute("cachedwithin");
if(attr!=null) {
Expression val = attr.getValue();
if(val instanceof LitLong)
cachedWithin=((LitLong)val).getLongValue();
}
String strAccess = ((LitString)access).getString();
int acc = ComponentUtil.toIntAccess(strAccess,-1);
if(acc==-1)
throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getStart());
Function func = new FunctionImpl(page,name, returnType,returnFormat, output, bufferOutput, acc, displayname,description,
hint,secureJson,verifyClient,localMode,cachedWithin,_abstract,_final, body, getStart(),getEnd());
// %**%
Map attrs = getAttributes();
Iterator it = attrs.entrySet().iterator();
HashMap<String,Attribute> metadatas=new HashMap<String,Attribute>();
while(it.hasNext()){
attr=(Attribute) ((Map.Entry)it.next()).getValue();
metadatas.put(attr.getName(),attr);
}
func.setMetaData(metadatas);
return func;
}
@Override
public FlowControlFinal getFlowControlFinal() {
return null;
}
}