Nasal-Interpreter/src/optimizer.cpp

156 lines
6.2 KiB
C++

#include "optimizer.h"
namespace nasal {
void optimizer::const_string(
binary_operator* node,
string_literal* left_node,
string_literal* right_node) {
if (node->get_operator_type()!=binary_operator::kind::concat) {
return;
}
const auto& left = left_node->get_content();
const auto& right = right_node->get_content();
node->set_optimized_string(
new string_literal(node->get_location(), left+right)
);
}
void optimizer::const_number(
binary_operator* node,
number_literal* left_node,
number_literal* right_node) {
const auto left = left_node->get_number();
const auto right = right_node->get_number();
f64 res;
switch(node->get_operator_type()) {
case binary_operator::kind::add: res = left+right; break;
case binary_operator::kind::sub: res = left-right; break;
case binary_operator::kind::mult: res = left*right; break;
case binary_operator::kind::div: res = left/right; break;
case binary_operator::kind::less: res = left<right; break;
case binary_operator::kind::leq: res = left<=right; break;
case binary_operator::kind::grt: res = left>right; break;
case binary_operator::kind::geq: res = left>=right; break;
case binary_operator::kind::bitwise_or:
res = static_cast<i32>(left)|static_cast<i32>(right); break;
case binary_operator::kind::bitwise_xor:
res = static_cast<i32>(left)^static_cast<i32>(right); break;
case binary_operator::kind::bitwise_and:
res = static_cast<i32>(left)&static_cast<i32>(right); break;
default: return;
}
if (std::isinf(res) || std::isnan(res)) {
return;
}
node->set_optimized_number(
new number_literal(node->get_location(), res)
);
}
void optimizer::const_number(
unary_operator* node,
number_literal* value_node) {
auto res = value_node->get_number();
switch(node->get_operator_type()) {
case unary_operator::kind::negative:
res = -res; break;
case unary_operator::kind::bitwise_not:
res = ~static_cast<i32>(res); break;
case unary_operator::kind::logical_not:
res = !res; break;
}
if (std::isinf(res) || std::isnan(res)) {
return;
}
node->set_optimized_number(
new number_literal(node->get_location(), res)
);
}
bool optimizer::visit_binary_operator(binary_operator* node) {
auto left_node = node->get_left();
auto right_node = node->get_right();
left_node->accept(this);
right_node->accept(this);
number_literal* left_num_node = nullptr;
number_literal* right_num_node = nullptr;
string_literal* left_str_node = nullptr;
string_literal* right_str_node = nullptr;
if (left_node->get_type()==expr_type::ast_num) {
left_num_node = reinterpret_cast<number_literal*>(left_node);
} else if (left_node->get_type()==expr_type::ast_binary &&
reinterpret_cast<binary_operator*>(left_node)->get_optimized_number()) {
auto optimized = reinterpret_cast<binary_operator*>(left_node);
left_num_node = optimized->get_optimized_number();
} else if (left_node->get_type()==expr_type::ast_unary &&
reinterpret_cast<unary_operator*>(left_node)->get_optimized_number()) {
auto optimized = reinterpret_cast<unary_operator*>(left_node);
left_num_node = optimized->get_optimized_number();
}
if (right_node->get_type()==expr_type::ast_num) {
right_num_node = reinterpret_cast<number_literal*>(right_node);
} else if (right_node->get_type()==expr_type::ast_binary &&
reinterpret_cast<binary_operator*>(right_node)->get_optimized_number()) {
auto optimized = reinterpret_cast<binary_operator*>(right_node);
right_num_node = optimized->get_optimized_number();
} else if (right_node->get_type()==expr_type::ast_unary &&
reinterpret_cast<unary_operator*>(right_node)->get_optimized_number()) {
auto optimized = reinterpret_cast<unary_operator*>(right_node);
right_num_node = optimized->get_optimized_number();
}
if (left_node->get_type()==expr_type::ast_str) {
left_str_node = reinterpret_cast<string_literal*>(left_node);
} else if (left_node->get_type()==expr_type::ast_binary &&
reinterpret_cast<binary_operator*>(left_node)->get_optimized_string()) {
auto optimized = reinterpret_cast<binary_operator*>(left_node);
left_str_node = optimized->get_optimized_string();
}
if (right_node->get_type()==expr_type::ast_str) {
right_str_node = reinterpret_cast<string_literal*>(right_node);
} else if (right_node->get_type()==expr_type::ast_binary &&
reinterpret_cast<binary_operator*>(right_node)->get_optimized_string()) {
auto optimized = reinterpret_cast<binary_operator*>(right_node);
right_str_node = optimized->get_optimized_string();
}
if (left_num_node && right_num_node) {
const_number(node, left_num_node, right_num_node);
return true;
}
if (left_str_node && right_str_node) {
const_string(node, left_str_node, right_str_node);
return true;
}
return true;
}
bool optimizer::visit_unary_operator(unary_operator* node) {
auto value = node->get_value();
value->accept(this);
number_literal* num_node = nullptr;
if (value->get_type()==expr_type::ast_num) {
num_node = reinterpret_cast<number_literal*>(value);
} else if (value->get_type()==expr_type::ast_binary &&
reinterpret_cast<binary_operator*>(value)->get_optimized_number()) {
auto optimized = reinterpret_cast<binary_operator*>(value);
num_node = optimized->get_optimized_number();
} else if (value->get_type()==expr_type::ast_unary &&
reinterpret_cast<unary_operator*>(value)->get_optimized_number()) {
auto optimized = reinterpret_cast<unary_operator*>(value);
num_node = optimized->get_optimized_number();
}
if (num_node) {
const_number(node, num_node);
}
return true;
}
void optimizer::do_optimization(code_block* root) {
root->accept(this);
}
}