dvander@212: /* vim: set ts=4 sw=4 tw=99 et: dvander@212: * dvander@212: * Copyright (C) 2012 David Anderson dvander@212: * dvander@212: * This file is part of SourcePawn. dvander@212: * dvander@212: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@212: * the terms of the GNU General Public License as published by the Free dvander@212: * Software Foundation, either version 3 of the License, or (at your option) dvander@212: * any later version. dvander@212: * dvander@212: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@212: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@212: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@212: * dvander@212: * You should have received a copy of the GNU General Public License along with dvander@212: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@212: */ dvander@212: #include "AST.h" dvander@212: #include "ConstantEvaluator.h" dvander@213: #include "../Heap-inl.h" dvander@213: #include "../Handles-inl.h" dvander@212: dvander@212: using namespace ke; dvander@212: dvander@212: static inline bool dvander@212: EvaluateBinaryOperation(TokenKind kind, const BoxedPrimitive &left, const BoxedPrimitive &right, dvander@212: BoxedPrimitive *out) dvander@212: { dvander@212: switch (kind) { dvander@212: case TOK_PLUS: dvander@212: *out = BoxedPrimitive::Int(left.toInt() + right.toInt()); dvander@212: return true; dvander@212: dvander@212: case TOK_SHL: dvander@212: *out = BoxedPrimitive::Int(left.toInt() << right.toInt()); dvander@212: return true; dvander@212: dvander@212: default: dvander@212: return false; dvander@212: } dvander@212: } dvander@212: dvander@212: static inline bool dvander@212: EvaluateUnaryOperation(TokenKind kind, const BoxedPrimitive &inner, BoxedPrimitive *out) dvander@212: { dvander@212: switch (kind) { dvander@212: case TOK_MINUS: dvander@212: *out = BoxedPrimitive::Int(-inner.toInt()); dvander@212: return true; dvander@212: dvander@212: default: dvander@212: return false; dvander@212: } dvander@212: } dvander@212: dvander@212: bool dvander@212: ke::EvaluateForConstant(Expression *expr, BoxedPrimitive *out) dvander@212: { dvander@212: switch (expr->kind()) { dvander@212: case AstNode::kBinaryExpression: dvander@212: { dvander@212: BoxedPrimitive left; dvander@212: BoxedPrimitive right; dvander@212: BinaryExpression *b = expr->toBinaryExpression(); dvander@212: if (!EvaluateForConstant(b->left(), &left) || dvander@212: !EvaluateForConstant(b->right(), &right)) dvander@212: { dvander@212: return false; dvander@212: } dvander@212: return EvaluateBinaryOperation(b->token(), left, right, out); dvander@212: } dvander@212: dvander@212: case AstNode::kUnaryExpression: dvander@212: { dvander@212: BoxedPrimitive inner; dvander@212: UnaryExpression *u = expr->toUnaryExpression(); dvander@212: if (!EvaluateForConstant(u->expression(), &inner)) dvander@212: return false; dvander@212: return EvaluateUnaryOperation(u->token(), inner, out); dvander@212: } dvander@212: dvander@212: case AstNode::kBooleanLiteral: dvander@212: *out = BoxedPrimitive::Int(expr->toBooleanLiteral()->token() == TOK_TRUE ? 1 : 0); dvander@212: return true; dvander@212: dvander@212: case AstNode::kIntegerLiteral: dvander@212: *out = BoxedPrimitive::Int(expr->toIntegerLiteral()->value()); dvander@212: return true; dvander@212: dvander@212: default: dvander@212: return false; dvander@212: } dvander@212: }