Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
prompto.expression.EqualsExpression Maven / Gradle / Ivy
package prompto.expression;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import prompto.compiler.ClassConstant;
import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.IInstructionListener;
import prompto.compiler.IOperatorFunction;
import prompto.compiler.IVerifierEntry.VerifierType;
import prompto.compiler.InterfaceConstant;
import prompto.compiler.MethodConstant;
import prompto.compiler.MethodInfo;
import prompto.compiler.OffsetListenerConstant;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.compiler.ShortOperand;
import prompto.compiler.StackLocal;
import prompto.compiler.StackState;
import prompto.compiler.StringConstant;
import prompto.declaration.AttributeDeclaration;
import prompto.declaration.TestMethodDeclaration;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.grammar.EqOp;
import prompto.grammar.INamed;
import prompto.grammar.Identifier;
import prompto.intrinsic.PromptoAny;
import prompto.intrinsic.PromptoDate;
import prompto.intrinsic.PromptoDateTime;
import prompto.intrinsic.PromptoDict;
import prompto.intrinsic.PromptoDocument;
import prompto.intrinsic.PromptoList;
import prompto.intrinsic.PromptoPeriod;
import prompto.intrinsic.PromptoProxy;
import prompto.intrinsic.PromptoRange;
import prompto.intrinsic.PromptoSet;
import prompto.intrinsic.PromptoTime;
import prompto.intrinsic.PromptoVersion;
import prompto.literal.NullLiteral;
import prompto.parser.CodeSection;
import prompto.parser.Dialect;
import prompto.runtime.Context;
import prompto.runtime.LinkedValue;
import prompto.runtime.LinkedVariable;
import prompto.runtime.Variable;
import prompto.store.AttributeInfo;
import prompto.store.DataStore;
import prompto.store.IQueryBuilder;
import prompto.store.IQueryBuilder.MatchOp;
import prompto.store.IStore;
import prompto.transpiler.Transpiler;
import prompto.type.AnyType;
import prompto.type.BooleanType;
import prompto.type.CategoryType;
import prompto.type.CharacterType;
import prompto.type.ContainerType;
import prompto.type.DateTimeType;
import prompto.type.DateType;
import prompto.type.DecimalType;
import prompto.type.DocumentType;
import prompto.type.DictType;
import prompto.type.IType;
import prompto.type.IntegerType;
import prompto.type.ListType;
import prompto.type.MethodType;
import prompto.type.NullType;
import prompto.type.PeriodType;
import prompto.type.RangeType;
import prompto.type.SetType;
import prompto.type.TextType;
import prompto.type.TimeType;
import prompto.type.UuidType;
import prompto.type.VersionType;
import prompto.utils.CodeWriter;
import prompto.value.BooleanValue;
import prompto.value.IInstance;
import prompto.value.IValue;
import prompto.value.NullValue;
import prompto.value.TypeValue;
public class EqualsExpression extends CodeSection implements IPredicate, IAssertion {
IExpression left;
EqOp operator;
IExpression right;
public EqualsExpression(IExpression left, EqOp operator, IExpression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
@Override
public String toString() {
return left.toString() + ' ' + operator.toString() + ' ' + right.toString();
}
static final String VOWELS = "AEIO"; // sufficient here
@Override
public void toDialect(CodeWriter writer) {
left.toDialect(writer);
writer.append(" ");
writer.append(operator.toString(writer.getDialect()));
// make this a AN
if(operator==EqOp.IS_A || operator==EqOp.IS_NOT_A) {
String name = right.toString();
if(VOWELS.indexOf(name.charAt(0))>=0)
writer.append("n");
}
writer.append(" ");
right.toDialect(writer);
}
@Override
public IType check(Context context) {
IType lt = left.check(context);
if(lt instanceof ContainerType)
lt = ((ContainerType)lt).getItemType();
IType rt = right.check(context);
if(rt instanceof ContainerType)
rt = ((ContainerType)rt).getItemType();
switch(operator) {
case CONTAINS:
case NOT_CONTAINS:
if(lt!=TextType.instance() || (rt!=TextType.instance() && rt!=CharacterType.instance()))
throw new SyntaxError("'contains' only operates on textual values!");
default:
return BooleanType.instance(); // can compare all objects
}
}
@Override
public Context checkAssert(Context context) {
check(context);
// need to optionally auto-downcast
context = downcastForCheck(context);
return context;
}
@Override
public IValue interpret(Context context) throws PromptoError {
IValue lval = left.interpret(context);
if(lval==null)
lval = NullValue.instance();
IValue rval = right.interpret(context);
if(rval==null)
rval = NullValue.instance();
return interpret(context, lval, rval);
}
private IValue interpret(Context context, IValue lval, IValue rval) throws PromptoError {
boolean equal = false;
switch(operator) {
case IS:
equal = lval==rval;
break;
case IS_NOT:
equal = lval!=rval;
break;
case IS_A:
equal = interpretIsA(context,lval,rval);
break;
case IS_NOT_A:
equal = !interpretIsA(context,lval,rval);
break;
case EQUALS:
equal = interpretEquals(context,lval,rval);
break;
case NOT_EQUALS:
equal = !interpretEquals(context,lval,rval);
break;
case ROUGHLY:
equal = lval.roughly(context, rval);
break;
case CONTAINS:
equal = interpretContains(context,lval,rval);
break;
case NOT_CONTAINS:
equal = !interpretContains(context,lval,rval);
break;
}
return BooleanValue.valueOf(equal); }
private boolean interpretIsA(Context context, IValue lval, IValue rval) throws PromptoError {
IType actual = lval.getType();
if(actual==NullType.instance())
return false;
IType expected = ((TypeValue)rval).getValue();
return expected.isAssignableFrom(context, actual);
}
private boolean interpretEquals(Context context, IValue lval, IValue rval) throws PromptoError {
if(lval==rval)
return true;
else if(lval==NullValue.instance() || rval==NullValue.instance())
return false;
else
return lval.equals(rval);
}
private boolean interpretContains(Context context, IValue lval, IValue rval) throws PromptoError {
if(lval==rval)
return true;
else if(lval==NullValue.instance() || rval==NullValue.instance())
return false;
else
return lval.contains(context, rval);
}
public Context downcastForCheck(Context context) {
try {
return downcast(context, false);
} catch(PromptoError e) {
throw new RuntimeException("Should never get there!");
}
}
public Context downcastForInterpret(Context context) throws PromptoError {
return downcast(context, true);
}
private Context downcast(Context context, boolean setValue) throws PromptoError {
if(operator==EqOp.IS_A) {
Identifier name = readLeftName();
if(name!=null && right instanceof TypeExpression) {
INamed value = context.getRegisteredValue(INamed.class, name);
if(value!=null) {
IType targetType = ((TypeExpression)right).getType().resolve(context, null);
IType sourceType = value.getType(context);
if(sourceType.isMutable(context))
targetType = targetType.asMutable(context, true);
value = new LinkedVariable(targetType, value);
Context local = context.newChildContext();
local.registerInstance(value, false);
if(setValue)
local.setValue(name, new LinkedValue(context, targetType));
context = local;
}
}
}
return context;
}
public Context prepareAutodowncast(Context context, MethodInfo method) {
if(operator==EqOp.IS_A) {
Identifier name = readLeftName();
if(name!=null && right instanceof TypeExpression) {
IType type = ((TypeExpression)right).getType().resolve(context, null);
ClassConstant c = new ClassConstant(type.toJavaType(context));
StackLocal local = method.getRegisteredLocal(name.toString());
((StackLocal.ObjectLocal)local).markForAutodowncast(c);
return downcastForCheck(context);
}
}
return context;
}
public void cancelAutodowncast(Context context, MethodInfo method) {
if(operator==EqOp.IS_A) {
Identifier name = readLeftName();
if(name!=null) {
StackLocal local = method.getRegisteredLocal(name.toString());
((StackLocal.ObjectLocal)local).unmarkForAutodowncast();
}
}
}
private Identifier readLeftName() {
if(left instanceof InstanceExpression)
return ((InstanceExpression)left).getId();
else if(left instanceof UnresolvedIdentifier)
return ((UnresolvedIdentifier)left).getId();
return null;
}
@Override
public boolean interpretAssert(Context context, TestMethodDeclaration test) throws PromptoError {
IValue lval = left.interpret(context);
IValue rval = right.interpret(context);
IValue result = interpret(context, lval, rval);
if(result==BooleanValue.TRUE)
return true;
String expected = buildExpectedMessage(context, test);
String actual = buildActualMessage(context, test, lval, rval);
test.printFailedAssertion(context, expected, actual);
return false;
}
private String buildActualMessage(Context context, TestMethodDeclaration test, IValue lval, IValue rval) {
switch(operator) {
case IS_A:
case IS_NOT_A:
return lval.getType().toString() + " " + operator.toString(test.getDialect()) + " " + rval.toString();
default:
return lval.toString() + " " + operator.toString(test.getDialect()) + " " + rval.toString();
}
}
private String buildExpectedMessage(Context context, TestMethodDeclaration test) {
CodeWriter writer = new CodeWriter(test.getDialect(), context);
this.toDialect(writer);
return writer.toString();
}
@Override
public void compileAssert(Context context, MethodInfo method, Flags flags, TestMethodDeclaration test) {
context = context.newChildContext();
StackState finalState = method.captureStackState();
// compile left and store in local
IType leftType = this.left.check(context);
ResultInfo leftInfo = this.left.compile(context, method, flags.withPrimitive(false));
String leftName = method.nextTransientName("left");
StackLocal left = method.registerLocal(leftName, VerifierType.ITEM_Object, new ClassConstant(leftInfo.getType()));
CompilerUtils.compileASTORE(method, left);
// compile right and store in local
IType rightType = this.right.check(context);
ResultInfo rightInfo = this.right.compile(context, method, flags.withPrimitive(false));
String rightName = method.nextTransientName("right");
StackLocal right = method.registerLocal(rightName, VerifierType.ITEM_Object, new ClassConstant(rightInfo.getType()));
CompilerUtils.compileASTORE(method, right);
// call regular compile
IExpression newLeft = new InstanceExpression(new Identifier(leftName));
context.registerInstance(new Variable(new Identifier(leftName), leftType));
IExpression newRight = this.right instanceof TypeExpression ? this.right : new InstanceExpression(new Identifier(rightName));
context.registerInstance(new Variable(new Identifier(rightName), rightType));
EqualsExpression newExp = new EqualsExpression(newLeft, this.operator, newRight);
ResultInfo info = newExp.compile(context, method, flags.withPrimitive(true));
if(BooleanValue.class==info.getType())
CompilerUtils.BooleanToboolean(method);
// 1 = success
IInstructionListener finalListener = method.addOffsetListener(new OffsetListenerConstant());
method.activateOffsetListener(finalListener);
method.addInstruction(Opcode.IFNE, finalListener);
// increment failure counter
method.addInstruction(Opcode.ICONST_1);
method.addInstruction(Opcode.IADD);
// build failure message
String message = buildExpectedMessage(context, test);
message = test.buildFailedAssertionMessagePrefix(message);
method.addInstruction(Opcode.LDC, new StringConstant(message));
CompilerUtils.compileALOAD(method, left);
MethodConstant stringValueOf = new MethodConstant(String.class, "valueOf", Object.class, String.class);
method.addInstruction(Opcode.INVOKESTATIC, stringValueOf);
MethodConstant concat = new MethodConstant(String.class, "concat", String.class, String.class);
method.addInstruction(Opcode.INVOKEVIRTUAL, concat);
method.addInstruction(Opcode.LDC, new StringConstant(" " + operator.toString(test.getDialect()) + " "));
method.addInstruction(Opcode.INVOKEVIRTUAL, concat);
CompilerUtils.compileALOAD(method, right);
method.addInstruction(Opcode.INVOKESTATIC, stringValueOf);
method.addInstruction(Opcode.INVOKEVIRTUAL, concat);
test.compileFailure(context, method, flags);
// success/final
method.unregisterLocal(right);
method.unregisterLocal(left);
method.restoreFullStackState(finalState);
method.placeLabel(finalState);
method.inhibitOffsetListener(finalListener);
}
@Override
public void checkQuery(Context context) throws PromptoError {
AttributeDeclaration decl = left.checkAttribute(context, this);
if(decl==null)
return;
if(!decl.isStorable(context)) {
context.getProblemListener().reportNotStorable(this, decl.getName());
return;
}
right.check(context);
}
@Override
public void interpretQuery(Context context, IQueryBuilder query, IStore store) throws PromptoError {
AttributeInfo info = left.checkAttributeInfo(context, this, store);
if(info==null)
throw new SyntaxError("Unable to interpret predicate: " + this.toString());
IValue value = right.interpret(context);
if(value instanceof IInstance)
value = ((IInstance)value).getMember(context, new Identifier(IStore.dbIdName), false);
Object data = null;
if(value!=null)
if(IStore.dbIdName.equals(info.getName()))
data = DataStore.getInstance().convertToNativeDbId(value);
else
data = value.getStorableData();
MatchOp match = getMatchOp();
query.verify(info, match, data);
if(operator.isNot())
query.not();
}
private MatchOp getMatchOp() {
switch(operator) {
case IS:
case IS_NOT:
case EQUALS:
case NOT_EQUALS:
return MatchOp.EQUALS;
case ROUGHLY:
return MatchOp.ROUGHLY;
case CONTAINS:
case NOT_CONTAINS:
return MatchOp.CONTAINS;
default:
throw new UnsupportedOperationException();
}
}
@Override
public void compileQuery(Context context, MethodInfo method, Flags flags) {
compileAttributeInfo(context, method, flags);
MatchOp match = getMatchOp();
CompilerUtils.compileJavaEnum(context, method, flags, match);
right.compile(context, method, flags);
InterfaceConstant m = new InterfaceConstant(IQueryBuilder.class,
"verify", AttributeInfo.class, MatchOp.class, Object.class, IQueryBuilder.class);
method.addInstruction(Opcode.INVOKEINTERFACE, m);
if(operator.isNot()) {
m = new InterfaceConstant(IQueryBuilder.class, "not", IQueryBuilder.class);
method.addInstruction(Opcode.INVOKEINTERFACE, m);
}
}
private void compileAttributeInfo(Context context, MethodInfo method, Flags flags) {
AttributeDeclaration decl = left.checkAttribute(context, this);
if(decl==null || !decl.isStorable(context))
throw new SyntaxError("Unable to compile predicate");
if(!decl.isStorable(context)) {
context.getProblemListener().reportNotStorable(this, decl.getName());
return;
}
AttributeInfo info = context.findAttribute(decl.getName()).getAttributeInfo(context);
CompilerUtils.compileAttributeInfo(context, method, flags, info);
}
static Map, IOperatorFunction> EQUALS_COMPILERS = createEqualsCompilers();
private static Map, IOperatorFunction> createEqualsCompilers() {
Map, IOperatorFunction> map = new HashMap<>();
map.put(boolean.class, BooleanType::compileEquals);
map.put(java.lang.Boolean.class, BooleanType::compileEquals);
map.put(char.class, CharacterType::compileEquals);
map.put(java.lang.Character.class, CharacterType::compileEquals);
map.put(String.class, TextType::compileEquals);
map.put(double.class, DecimalType::compileEquals);
map.put(Double.class, DecimalType::compileEquals);
map.put(long.class, IntegerType::compileEquals);
map.put(Long.class, IntegerType::compileEquals);
map.put(PromptoAny.class, AnyType::compileEquals);
map.put(PromptoRange.Long.class, RangeType::compileEquals);
map.put(PromptoRange.Character.class, RangeType::compileEquals);
map.put(PromptoRange.Date.class, RangeType::compileEquals);
map.put(PromptoRange.Time.class, RangeType::compileEquals);
map.put(PromptoDate.class, DateType::compileEquals);
map.put(PromptoDateTime.class, DateTimeType::compileEquals);
map.put(PromptoTime.class, TimeType::compileEquals);
map.put(PromptoPeriod.class, PeriodType::compileEquals);
map.put(PromptoVersion.class, VersionType::compileEquals);
map.put(PromptoDict.class, DictType::compileEquals);
map.put(PromptoDocument.class, DocumentType::compileEquals);
map.put(PromptoSet.class, SetType::compileEquals); /*
map.put(PromptoTuple.class, TupleValue::compileEquals); */
map.put(PromptoList.class, ListType::compileEquals);
map.put(UUID.class, UuidType::compileEquals);
map.put(Object.class, AnyType::compileEquals);
return map;
}
static Map, IOperatorFunction> CONTAINS_COMPILERS = createContainsCompilers();
private static Map, IOperatorFunction> createContainsCompilers() {
Map, IOperatorFunction> map = new HashMap<>();
map.put(String.class, TextType::compileContains);
/*
map.put(PromptoRange.Long.class, RangeBase::compileContains);
map.put(PromptoRange.Character.class, RangeBase::compileContains);
map.put(PromptoRange.Date.class, RangeBase::compileContains);
map.put(PromptoRange.Time.class, RangeBase::compileContains);
map.put(PromptoSet.class, SetValue::compileContains);
map.put(PromptoTuple.class, TupleValue::compileContains);
map.put(PromptoList.class, ListValue::compileContains);
*/
return map;
}
@Override
public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
switch(operator) {
case EQUALS:
return compileEquals(context, method, flags.withReverse(false));
case NOT_EQUALS:
return compileEquals(context, method, flags.withReverse(true));
case ROUGHLY:
return compileEquals(context, method, flags.withReverse(false).withRoughly(true));
case CONTAINS:
return compileContains(context, method, flags.withReverse(false));
case NOT_CONTAINS:
return compileContains(context, method, flags.withReverse(true));
case IS:
return compileIs(context, method, flags.withReverse(false));
case IS_NOT:
return compileIs(context, method, flags.withReverse(true));
case IS_A:
return compileIsA(context, method, flags.withReverse(false));
case IS_NOT_A:
return compileIsA(context, method, flags.withReverse(true));
default:
throw new UnsupportedOperationException();
}
}
private ResultInfo compileIsA(Context context, MethodInfo method, Flags flags) {
if(!(this.right instanceof TypeExpression))
throw new Error("Cannot compile:" + this.right.getClass().getName());
IType type = ((TypeExpression)this.right).getType().resolve(context, null);
if(type instanceof MethodType)
compileIsAMethodType(context, method, flags, (MethodType)type);
else
compileIsAnInstance(context, method, flags);
if(flags.isReverse())
CompilerUtils.reverseBoolean(method);
if(flags.toPrimitive())
return new ResultInfo(boolean.class);
else
return CompilerUtils.booleanToBoolean(method);
}
private void compileIsAMethodType(Context context, MethodInfo method, Flags flags, MethodType target) {
// the reference we are checking
left.compile(context, method, flags.withPrimitive(false));
// what interface we would be casting to
ClassConstant dest = new ClassConstant(target.toJavaType(context));
method.addInstruction(Opcode.LDC, dest);
// call helper
MethodConstant m = new MethodConstant(PromptoProxy.class, "isProxyableTo", Object.class, Class.class, boolean.class);
method.addInstruction(Opcode.INVOKESTATIC, m);
}
private void compileIsAnInstance(Context context, MethodInfo method, Flags flags) {
right.compile(context, method, flags.withPrimitive(false));
left.compile(context, method, flags.withPrimitive(false));
MethodConstant m = new MethodConstant(Class.class, "isInstance", Object.class, boolean.class);
method.addInstruction(Opcode.INVOKEVIRTUAL, m);
}
public ResultInfo compileIs(Context context, MethodInfo method, Flags flags) {
if(left.equals(right))
method.addInstruction(flags.isReverse() ? Opcode.ICONST_0 : Opcode.ICONST_1);
else if(left instanceof NullLiteral)
compileIsNull(context, method, flags, right);
else if(right instanceof NullLiteral)
compileIsNull(context, method, flags, left);
else
compileIsInstance(context, method, flags);
if(flags.toPrimitive())
return new ResultInfo(boolean.class);
else
return CompilerUtils.booleanToBoolean(method);
}
private void compileIsNull(Context context, MethodInfo method, Flags flags, IExpression value) {
StackState initialState = method.captureStackState();
value.compile(context, method, flags.withPrimitive(false));
Opcode opcode = flags.isReverse() ? Opcode.IFNONNULL : Opcode.IFNULL;
method.addInstruction(opcode, new ShortOperand((short)7));
compileIsEpilogue(context, method, flags, initialState);
}
private void compileIsEpilogue(Context context, MethodInfo method, Flags flags, StackState initialState) {
method.addInstruction(Opcode.ICONST_0);
method.addInstruction(Opcode.GOTO, new ShortOperand((short)4));
method.restoreFullStackState(initialState);
method.placeLabel(initialState);
method.addInstruction(Opcode.ICONST_1);
StackState lastState = method.captureStackState();
method.placeLabel(lastState);
}
private void compileIsInstance(Context context, MethodInfo method, Flags flags) {
StackState initialState = method.captureStackState();
left.compile(context, method, flags.withPrimitive(false));
right.compile(context, method, flags.withPrimitive(false));
Opcode opcode = flags.isReverse() ? Opcode.IF_ACMPNE : Opcode.IF_ACMPEQ;
method.addInstruction(opcode, new ShortOperand((short)7));
compileIsEpilogue(context, method, flags, initialState);
}
public ResultInfo compileEquals(Context context, MethodInfo method, Flags flags) {
ResultInfo lval = left.compile(context, method, flags.withPrimitive(true));
Type ltype = lval.isPromptoCategory() ? Object.class : lval.getType();
IOperatorFunction compiler = getEqualsCompiler(ltype);
if(compiler==null) {
System.err.println("Missing IOperatorFunction for = " + lval.getType().getTypeName());
throw new SyntaxError("Cannot check equality of " + lval.getType().getTypeName() + " with " + right.check(context).getFamilyInfo(context));
}
return compiler.compile(context, method, flags, lval, right);
}
private IOperatorFunction getEqualsCompiler(Type type) {
IOperatorFunction function = EQUALS_COMPILERS.get(type);
if(function==null && CompilerUtils.isEnumNativeType(type))
return NativeSymbol::compileEquals;
return function;
}
public ResultInfo compileContains(Context context, MethodInfo method, Flags flags) {
ResultInfo lval = left.compile(context, method, flags.withPrimitive(true));
IOperatorFunction compiler = CONTAINS_COMPILERS.get(lval.getType());
if(compiler==null) {
System.err.println("Missing IOperatorFunction for 'contains' " + lval.getType().getTypeName());
throw new SyntaxError("Cannot check that " + lval.getType().getTypeName() + " contains " + right.check(context).getFamilyInfo(context));
}
return compiler.compile(context, method, flags, lval, right);
}
@Override
public void declare(Transpiler transpiler) {
this.left.declare(transpiler);
this.right.declare(transpiler);
if(this.operator == EqOp.ROUGHLY) {
transpiler.require("removeAccents");
}
}
@Override
public boolean transpile(Transpiler transpiler) {
switch (this.operator) {
case EQUALS:
this.transpileEquals(transpiler);
break;
case NOT_EQUALS:
this.transpileNotEquals(transpiler);
break;
case ROUGHLY:
this.transpileRoughly(transpiler);
break;
case CONTAINS:
this.transpileContains(transpiler);
break;
case NOT_CONTAINS:
this.transpileNotContains(transpiler);
break;
case IS:
this.transpileIs(transpiler);
break;
case IS_NOT:
this.transpileIsNot(transpiler);
break;
case IS_A:
this.transpileIsA(transpiler);
break;
case IS_NOT_A:
this.transpileIsNotA(transpiler);
break;
default:
throw new Error("Cannot transpile:" + this.operator.toString());
}
return false;
}
private void transpileIsNotA(Transpiler transpiler) {
transpiler.append("!(");
transpileIsA(transpiler);
transpiler.append(")");
}
private void transpileIsA(Transpiler transpiler) {
if(!(this.right instanceof TypeExpression))
throw new Error("Cannot transpile:" + this.right.getClass().getName());
IType type = ((TypeExpression)this.right).getType().resolve(transpiler.getContext(), null);
if(type==BooleanType.instance()) {
transpiler.append("isABoolean(");
this.left.transpile(transpiler);
transpiler.append(")");
} else if(type==IntegerType.instance()) {
transpiler.append("isAnInteger(");
this.left.transpile(transpiler);
transpiler.append(")");
} else if(type==DecimalType.instance()) {
transpiler.append("isADecimal(");
this.left.transpile(transpiler);
transpiler.append(")");
} else if(type==TextType.instance()) {
transpiler.append("isAText(");
this.left.transpile(transpiler);
transpiler.append(")");
} else if(type==CharacterType.instance()) {
transpiler.append("isACharacter(");
this.left.transpile(transpiler);
transpiler.append(")");
} else if(type instanceof MethodType) {
transpiler.append("isAMethod(");
this.left.transpile(transpiler);
transpiler.append(", ");
((MethodType)type).transpileMethodType(transpiler);
transpiler.append(")");
} else if(type instanceof CategoryType) {
transpiler.append("isInstanceOf(");
this.left.transpile(transpiler);
transpiler.append(", ");
this.right.transpile(transpiler);
transpiler.append(")");
} else {
this.left.transpile(transpiler);
transpiler.append(" instanceof ");
this.right.transpile(transpiler);
}
}
private void transpileRoughly(Transpiler transpiler) {
transpiler.append("removeAccents(");
this.left.transpile(transpiler);
transpiler.append(").toLowerCase() === removeAccents(");
this.right.transpile(transpiler);
transpiler.append(").toLowerCase()");
}
private void transpileIsNot(Transpiler transpiler) {
this.left.transpile(transpiler);
transpiler.append(" !== ");
this.right.transpile(transpiler);
}
private void transpileIs(Transpiler transpiler) {
this.left.transpile(transpiler);
transpiler.append(" === ");
this.right.transpile(transpiler);
}
private void transpileEquals(Transpiler transpiler) {
IType lt = this.left.check(transpiler.getContext());
if(lt == BooleanType.instance() || lt == IntegerType.instance() || lt == DecimalType.instance() || lt == CharacterType.instance() || lt == TextType.instance()) {
this.left.transpile(transpiler);
transpiler.append(" === ");
this.right.transpile(transpiler);
} else {
this.left.transpile(transpiler);
transpiler.append(".equals(");
this.right.transpile(transpiler);
transpiler.append(")");
}
}
private void transpileNotEquals(Transpiler transpiler) {
IType lt = this.left.check(transpiler.getContext());
if(lt == BooleanType.instance() || lt == IntegerType.instance() || lt == DecimalType.instance() || lt == CharacterType.instance() || lt == TextType.instance()) {
this.left.transpile(transpiler);
transpiler.append(" !== ");
this.right.transpile(transpiler);
} else {
transpiler.append("!");
this.left.transpile(transpiler);
transpiler.append(".equals(");
this.right.transpile(transpiler);
transpiler.append(")");
}
}
private void transpileContains(Transpiler transpiler) {
this.left.transpile(transpiler);
transpiler.append(".contains(");
this.right.transpile(transpiler);
transpiler.append(")");
};
private void transpileNotContains(Transpiler transpiler) {
transpiler.append("!");
transpileNotContains(transpiler);
}
@Override
public void declareQuery(Transpiler transpiler) {
transpiler.require("MatchOp");
this.left.declare(transpiler);
this.right.declare(transpiler);
}
@Override
public void transpileQuery(Transpiler transpiler, String builderName) {
AttributeDeclaration decl = left.checkAttribute(transpiler.getContext(), this);
if(decl==null || !decl.isStorable(transpiler.getContext()))
throw new SyntaxError("Unable to interpret predicate");
AttributeInfo info = decl.getAttributeInfo(transpiler.getContext());
MatchOp matchOp = this.getMatchOp();
// TODO check for dbId field of instance value
transpiler.append(builderName).append(".verify(").append(info.toTranspiled()).append(", MatchOp.").append(matchOp.name()).append(", ");
right.transpile(transpiler);
transpiler.append(");").newLine();
if (operator.isNot())
transpiler.append(builderName).append(".not();").newLine();
}
@Override
public void transpileFound(Transpiler transpiler, Dialect dialect) {
transpiler.append("(");
this.left.transpile(transpiler);
transpiler.append(") + ' ").append(this.operator.toString(dialect)).append(" ' + (");
this.right.transpile(transpiler);
transpiler.append(")");
}
}