/**
* Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.transformer.bytecode;
import lucee.runtime.config.Config;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.op.Caster;
import lucee.runtime.type.util.KeyConstants;
import lucee.transformer.Context;
import lucee.transformer.Factory;
import lucee.transformer.Position;
import lucee.transformer.TransformerException;
import lucee.transformer.bytecode.cast.CastBoolean;
import lucee.transformer.bytecode.cast.CastDouble;
import lucee.transformer.bytecode.cast.CastInt;
import lucee.transformer.bytecode.cast.CastString;
import lucee.transformer.bytecode.expression.var.DataMemberImpl;
import lucee.transformer.bytecode.expression.var.EmptyArray;
import lucee.transformer.bytecode.expression.var.EmptyStruct;
import lucee.transformer.bytecode.expression.var.VariableImpl;
import lucee.transformer.bytecode.literal.LitBooleanImpl;
import lucee.transformer.bytecode.literal.LitDoubleImpl;
import lucee.transformer.bytecode.literal.LitFloatImpl;
import lucee.transformer.bytecode.literal.LitIntegerImpl;
import lucee.transformer.bytecode.literal.LitLongImpl;
import lucee.transformer.bytecode.literal.LitStringImpl;
import lucee.transformer.bytecode.literal.Null;
import lucee.transformer.bytecode.op.OpBool;
import lucee.transformer.bytecode.op.OpString;
import lucee.transformer.bytecode.util.Types;
import lucee.transformer.expression.ExprBoolean;
import lucee.transformer.expression.ExprDouble;
import lucee.transformer.expression.ExprInt;
import lucee.transformer.expression.ExprString;
import lucee.transformer.expression.Expression;
import lucee.transformer.expression.literal.LitBoolean;
import lucee.transformer.expression.literal.LitDouble;
import lucee.transformer.expression.literal.LitFloat;
import lucee.transformer.expression.literal.LitInteger;
import lucee.transformer.expression.literal.LitLong;
import lucee.transformer.expression.literal.LitString;
import lucee.transformer.expression.literal.Literal;
import lucee.transformer.expression.var.DataMember;
import lucee.transformer.expression.var.Variable;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
public class BytecodeFactory extends Factory {
private final static Method INIT= new Method("init",
Types.COLLECTION_KEY,
new Type[]{Types.STRING});
private static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class);
private static BytecodeFactory instance;
public static Factory getInstance(Config config) {
if(instance==null)
instance=new BytecodeFactory(config==null?ThreadLocalPageContext.getConfig():config);
return instance;
}
private final LitBoolean TRUE;
private final LitBoolean FALSE;
private final LitString EMPTY;
private final LitString NULL;
private final LitDouble DOUBLE_ZERO;
private final LitDouble DOUBLE_ONE;
private final Config config;
public BytecodeFactory(Config config){
TRUE=createLitBoolean(true);
FALSE=createLitBoolean(false);
EMPTY=createLitString("");
NULL=createLitString("NULL");
DOUBLE_ZERO=createLitDouble(0);
DOUBLE_ONE=createLitDouble(1);
this.config=config;
}
@Override
public LitString createLitString(String str) {
return new LitStringImpl(this,str,null,null);
}
@Override
public LitString createLitString(String str, Position start, Position end) {
return new LitStringImpl(this,str,start,end);
}
@Override
public LitBoolean createLitBoolean(boolean b) {
return new LitBooleanImpl(this, b, null, null);
}
@Override
public LitBoolean createLitBoolean(boolean b, Position start, Position end) {
return new LitBooleanImpl(this, b, start, end);
}
@Override
public LitDouble createLitDouble(double d) {
return new LitDoubleImpl(this, d, null, null);
}
@Override
public LitDouble createLitDouble(double d, Position start, Position end) {
return new LitDoubleImpl(this, d, start, end);
}
@Override
public LitFloat createLitFloat(float f) {
return new LitFloatImpl(this, f, null, null);
}
@Override
public LitFloat createLitFloat(float f, Position start, Position end) {
return new LitFloatImpl(this, f, start, end);
}
@Override
public LitLong createLitLong(long l) {
return new LitLongImpl(this, l, null, null);
}
@Override
public LitLong createLitLong(long l, Position start, Position end) {
return new LitLongImpl(this, l, start, end);
}
@Override
public LitInteger createLitInteger(int i) {
return new LitIntegerImpl(this, i, null, null);
}
@Override
public LitInteger createLitInteger(int i, Position start, Position end) {
return new LitIntegerImpl(this, i, start, end);
}
@Override
public boolean isNull(Expression e) {
return e instanceof Null;
}
@Override
public Expression createNull() {
return new Null(this,null,null);
}
@Override
public Expression createNull(Position start, Position end) {
return new Null(this,start,end);
}
@Override
public DataMember createDataMember(ExprString name) {
return new DataMemberImpl(name);
}
@Override
public Literal createLiteral(Object obj,Literal defaultValue) {
if(obj instanceof Boolean) return createLitBoolean(((Boolean)obj).booleanValue());
if(obj instanceof Number) {
if(obj instanceof Float)return createLitFloat(((Float)obj).floatValue());
else if(obj instanceof Integer)return createLitInteger(((Integer)obj).intValue());
else if(obj instanceof Long)return createLitLong(((Long)obj).longValue());
else return createLitDouble(((Number)obj).doubleValue());
}
String str = Caster.toString(obj,null);
if(str!=null) return createLitString(str);
return defaultValue;
}
@Override
public LitBoolean TRUE() {
return TRUE;
}
@Override
public LitBoolean FALSE() {
return FALSE;
}
@Override
public LitString EMPTY() {
return EMPTY;
}
@Override
public LitDouble DOUBLE_ZERO() {
return DOUBLE_ZERO;
}
@Override
public LitDouble DOUBLE_ONE() {
return DOUBLE_ONE;
}
@Override
public LitString NULL() {
return NULL;
}
@Override
public ExprDouble toExprDouble(Expression expr) {
return CastDouble.toExprDouble(expr);
}
@Override
public ExprString toExprString(Expression expr) {
return CastString.toExprString(expr);
}
@Override
public ExprBoolean toExprBoolean(Expression expr) {
return CastBoolean.toExprBoolean(expr);
}
@Override
public ExprInt toExprInt(Expression expr) {
return CastInt.toExprInt(expr);
}
@Override
public Variable createVariable(Position start, Position end) {
return new VariableImpl(this, start, end);
}
@Override
public Variable createVariable(int scope,Position start, Position end) {
return new VariableImpl(this, scope, start, end);
}
@Override
public ExprString opString(Expression left,Expression right){
return OpString.toExprString(left, right,true);
}
@Override
public ExprString opString(Expression left, Expression right, boolean concatStatic) {
return OpString.toExprString(left, right, concatStatic);
}
@Override
public ExprBoolean opBool(Expression left,Expression right,int operation){
return OpBool.toExprBoolean(left, right,operation);
}
@Override
public void registerKey(Context c,Expression name,boolean doUpperCase) throws TransformerException {
BytecodeContext bc=(BytecodeContext) c;
if(name instanceof Literal) {
Literal l=(Literal) name;
LitString ls = name instanceof LitString?(LitString)l:c.getFactory().createLitString(l.getString());
if(doUpperCase){
ls=ls.duplicate();
ls.upperCase();
}
String key=KeyConstants.getFieldName(ls.getString());
if(key!=null){
bc.getAdapter().getStatic(KEY_CONSTANTS, key, Types.COLLECTION_KEY);
return;
}
int index=bc.registerKey(ls);
bc.getAdapter().visitVarInsn(Opcodes.ALOAD, 0);
bc.getAdapter().visitFieldInsn(Opcodes.GETFIELD, bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString());
bc.getAdapter().push(index);
bc.getAdapter().visitInsn(Opcodes.AALOAD);
//ExpressionUtil.writeOutSilent(lit,bc, Expression.MODE_REF);
//bc.getAdapter().invokeStatic(Page.KEY_IMPL, Page.KEY_INTERN);
return;
}
name.writeOut(bc, Expression.MODE_REF);
bc.getAdapter().invokeStatic(Page.KEY_IMPL, INIT);
//bc.getAdapter().invokeStatic(Types.CASTER, TO_KEY);
return;
}
@Override
public Config getConfig() {
return config;
}
@Override
public Expression createStruct() {
return new EmptyStruct(this);
}
@Override
public Expression createArray() {
return new EmptyArray(this);
}
}