// TODO: Unify this with the JIT bc generator binary expressions // https://theengineco.atlassian.net/browse/LOOM-640 // https://theengineco.atlassian.net/browse/LOOM-641 Expression *TypeCompiler::visit(BinaryOperatorExpression *expression) { Tokens *tok = Tokens::getSingletonPtr(); Expression *eleft = expression->leftExpression; Expression *eright = expression->rightExpression; // operator overloads lmAssert(eleft->type && eright->type, "Untyped binary expression"); const char *opmethod = tok->getOperatorMethodName(expression->op); if (opmethod) { MemberInfo *mi = eleft->type->findMember(opmethod); if (mi) { lmAssert(mi->isMethod(), "Non-method operator"); MethodInfo *method = (MethodInfo *)mi; lmAssert(method->isOperator(), "Non-operator method"); utArray<Expression *> args; args.push_back(eleft); args.push_back(eright); ExpDesc opcall; ExpDesc emethod; BC::singleVar(cs, &opcall, eleft->type->getName()); BC::expString(cs, &emethod, method->getName()); BC::expToNextReg(cs->fs, &opcall); BC::expToNextReg(cs->fs, &emethod); BC::expToVal(cs->fs, &emethod); BC::indexed(cs->fs, &opcall, &emethod); generateCall(&opcall, &args, method); expression->e = opcall; return expression; } } // dynamic cast if ((expression->op == &tok->KEYWORD_IS) || (expression->op == &tok->KEYWORD_INSTANCEOF) || (expression->op == &tok->KEYWORD_AS)) { lmAssert(eleft->type && eright->type, "Untype expression"); FuncState *fs = cs->fs; ExpDesc object; BC::singleVar(cs, &object, "Object"); ExpDesc method; if (expression->op == &tok->KEYWORD_IS) { BC::expString(cs, &method, "_is"); } else if (expression->op == &tok->KEYWORD_AS) { BC::expString(cs, &method, "_as"); } else { BC::expString(cs, &method, "_instanceof"); } BC::expToNextReg(fs, &object); BC::expToNextReg(fs, &method); BC::expToVal(fs, &method); BC::indexed(fs, &object, &method); utArray<Expression *> args; args.push_back(eleft); args.push_back(new StringLiteral(eright->type->getAssembly()->getName().c_str())); args.push_back(new NumberLiteral(eright->type->getTypeID())); generateCall(&object, &args); expression->e = object; return expression; } BinOpr op = getbinopr(expression->op); if (op == OPR_LOOM_ADD) { lmAssert(eleft->type && eright->type, "Untyped add operaton %i", lineNumber); int ncheck = 0; if (eleft->type->isEnum() || (eleft->type->getFullName() == "system.Number")) { ncheck++; } if (eright->type->isEnum() || (eright->type->getFullName() == "system.Number")) { ncheck++; } if (ncheck != 2) { op = OPR_CONCAT; } } // If we're concat'ing arbitrary types with a string, we need to coerce them // to strings with Object._toString otherwise the Lua VM will error when // it can't concat (which has strict rules, for instance cannot concat nil) if ((op == OPR_CONCAT) && ((eleft->type->getFullName() == "system.String") || (eright->type->getFullName() == "system.String"))) { // coerce left to string, must be done even for string types as they may be null coerceToString(eleft); BC::infix(cs->fs, op, &eleft->e); // coerce right to string, must be done even for string types as they may be null coerceToString(eright); // and the binary op BC::posFix(cs->fs, op, &eleft->e, &eright->e); // save off expression and return expression->e = eleft->e; return expression; } eleft->visitExpression(this); BC::infix(cs->fs, op, &eleft->e); eright->visitExpression(this); BC::posFix(cs->fs, op, &eleft->e, &eright->e); expression->e = eleft->e; // promote to register BC::expToNextReg(cs->fs, &expression->e); return expression; }
Expression *TypeCompiler::visit(AssignmentOperatorExpression *expression) { Tokens *tok = Tokens::getSingletonPtr(); BinOpr op = getassignmentopr(expression->type); lmAssert(op != OPR_NOBINOPR, "Unknown bin op on AssignentOperatorExpression"); Expression *eleft = expression->leftExpression; Expression *eright = expression->rightExpression; lmAssert(eleft->type, "Untyped error on left expression"); const char *opmethod = tok->getOperatorMethodName(expression->type); if (opmethod) { MemberInfo *mi = eleft->type->findMember(opmethod); if (mi) { lmAssert(mi->isMethod(), "Non-method operator"); MethodInfo *method = (MethodInfo *)mi; lmAssert(method->isOperator(), "Non-operator method"); utArray<Expression *> args; args.push_back(eright); ExpDesc opcall; ExpDesc emethod; eleft->visitExpression(this); opcall = eleft->e; BC::initExpDesc(&emethod, VKNUM, 0); emethod.u.nval = method->getOrdinal(); BC::expToNextReg(cs->fs, &opcall); BC::expToNextReg(cs->fs, &emethod); BC::expToVal(cs->fs, &emethod); BC::indexed(cs->fs, &opcall, &emethod); generateCall(&opcall, &args, method); expression->e = opcall; return expression; } } eleft->assignment = false; eleft->visitExpression(this); BC::infix(cs->fs, op, &eleft->e); eright->visitExpression(this); BC::expToNextReg(cs->fs, &eright->e); BC::posFix(cs->fs, op, &eleft->e, &eright->e); ExpDesc right = eleft->e; BC::expToNextReg(cs->fs, &right); memset(&eleft->e, 0, sizeof(ExpDesc)); eleft->assignment = true; eleft->visitExpression(this); ExpDesc left = eleft->e; if (eleft->memberInfo && eleft->memberInfo->isProperty()) { eright->e = right; generatePropertySet(&eleft->e, eright, false); } else { BC::storeVar(cs->fs, &left, &right); } return expression; }