ExprNodePtr BoolType::castValue (LContext &lcontext, const ExprNodePtr &expr) const { if (IntLiteralNodePtr x = expr.cast<IntLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (UIntLiteralNodePtr x = expr.cast<UIntLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (HalfLiteralNodePtr x = expr.cast<HalfLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); if (FloatLiteralNodePtr x = expr.cast<FloatLiteralNode>()) return lcontext.newBoolLiteralNode (x->lineNumber, (bool) x->value); return expr; }
ExprNodePtr IntType::evaluate (LContext &lcontext, const ExprNodePtr &expr) const { if (UnaryOpNodePtr unOp = expr.cast<UnaryOpNode>()) { IntLiteralNodePtr x = unOp->operand.cast<IntLiteralNode>(); if (x) { switch (unOp->op) { case TK_BITNOT: return lcontext.newIntLiteralNode (expr->lineNumber, ~x->value); case TK_MINUS: return lcontext.newIntLiteralNode (expr->lineNumber, -x->value); case TK_NOT: return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << asString() << "."); } } } if (BinaryOpNodePtr binOp = expr.cast<BinaryOpNode>()) { IntLiteralNodePtr x = evaluate(lcontext, binOp->leftOperand).cast<IntLiteralNode>(); IntLiteralNodePtr y = evaluate(lcontext, binOp->rightOperand).cast<IntLiteralNode>(); if (x && y) { switch (binOp->op) { case TK_AND: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value && y->value); case TK_BITAND: return lcontext.newIntLiteralNode (expr->lineNumber, x->value & y->value); case TK_BITOR: return lcontext.newIntLiteralNode (expr->lineNumber, x->value | y->value); case TK_BITXOR: return lcontext.newIntLiteralNode (expr->lineNumber, x->value ^ y->value); case TK_DIV: if (y->value != 0) { return lcontext.newIntLiteralNode (expr->lineNumber, x->value / y->value); } else { MESSAGE_LW (lcontext, ERR_DIV_ZERO, expr->lineNumber, "Warning: Division by zero " "(" << x->value << "/" << y->value << ")."); return lcontext.newIntLiteralNode (expr->lineNumber, 0); } case TK_EQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value == y->value); case TK_GREATER: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value > y->value); case TK_GREATEREQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value >= y->value); case TK_LEFTSHIFT: return lcontext.newIntLiteralNode (expr->lineNumber, x->value << y->value); case TK_LESS: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value < y->value); case TK_LESSEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value <= y->value); case TK_MINUS: return lcontext.newIntLiteralNode (expr->lineNumber, x->value - y->value); case TK_MOD: return lcontext.newIntLiteralNode (expr->lineNumber, x->value % y->value); case TK_NOTEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value != y->value); case TK_OR: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value || y->value); case TK_PLUS: return lcontext.newIntLiteralNode (expr->lineNumber, x->value + y->value); case TK_RIGHTSHIFT: return lcontext.newIntLiteralNode (expr->lineNumber, x->value >> y->value); case TK_TIMES: return lcontext.newIntLiteralNode (expr->lineNumber, x->value * y->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } } }
ExprNodePtr BoolType::evaluate (LContext &lcontext, const ExprNodePtr &expr) const { if (UnaryOpNodePtr unOp = expr.cast<UnaryOpNode>()) { BoolLiteralNodePtr x = unOp->operand.cast<BoolLiteralNode>(); if (x) { switch (unOp->op) { case TK_BITNOT: // // We use the C++ ! operation to evaluate the CTL expression ~x, // where x is of type bool. This ensures that ~true == false // and ~false == true. // return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); case TK_NOT: return lcontext.newBoolLiteralNode (expr->lineNumber, !x->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Cannot apply " << tokenAsString (unOp->op) << " " "operator to value of type " << asString() << "."); } } } if (BinaryOpNodePtr binOp = expr.cast<BinaryOpNode>()) { BoolLiteralNodePtr x = binOp->leftOperand.cast<BoolLiteralNode>(); BoolLiteralNodePtr y = binOp->rightOperand.cast<BoolLiteralNode>(); if (x && y) { switch (binOp->op) { case TK_AND: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value && y->value); case TK_BITAND: // // For the bit-wise &, | and ^ operators, we normalize bool // operands before applying the operators. This avoids // surprises, for example, true^true == true. // return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value & !!y->value); case TK_BITOR: return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value | !!y->value); case TK_BITXOR: return lcontext.newBoolLiteralNode (expr->lineNumber, !!x->value ^ !!y->value); case TK_EQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value == y->value); case TK_GREATER: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value > y->value); case TK_GREATEREQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value >= y->value); case TK_LESS: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value < y->value); case TK_LESSEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value <= y->value); case TK_NOTEQUAL: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value != y->value); case TK_OR: return lcontext.newBoolLiteralNode (expr->lineNumber, x->value || y->value); default: MESSAGE_LE (lcontext, ERR_OP_TYPE, expr->lineNumber, "Invalid operand types " "for " << tokenAsString (binOp->op) << " operator " "(" << binOp->leftOperand->type->asString() << " " << tokenAsString (binOp->op) << " " << binOp->rightOperand->type->asString() << ")."); } } } return expr; }