summaryrefslogtreecommitdiff
path: root/tiger-compiler/src/desugar/desugar-visitor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tiger-compiler/src/desugar/desugar-visitor.cc')
-rw-r--r--tiger-compiler/src/desugar/desugar-visitor.cc144
1 files changed, 144 insertions, 0 deletions
diff --git a/tiger-compiler/src/desugar/desugar-visitor.cc b/tiger-compiler/src/desugar/desugar-visitor.cc
new file mode 100644
index 0000000..770cdf6
--- /dev/null
+++ b/tiger-compiler/src/desugar/desugar-visitor.cc
@@ -0,0 +1,144 @@
+/**
+ ** \file desugar/desugar-visitor.cc
+ ** \brief Implementation of desugar::DesugarVisitor.
+ */
+
+#include <ast/all.hh>
+#include <ast/libast.hh>
+#include <desugar/desugar-visitor.hh>
+#include <misc/algorithm.hh>
+#include <misc/symbol.hh>
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+
+namespace desugar
+{
+ DesugarVisitor::DesugarVisitor(bool desugar_for_p, bool desugar_string_cmp_p)
+ : super_type()
+ , desugar_for_p_(desugar_for_p)
+ , desugar_string_cmp_p_(desugar_string_cmp_p)
+ {}
+
+ /*-----------------------------.
+ | Desugar string comparisons. |
+ `-----------------------------*/
+ void DesugarVisitor::operator()(const ast::OpExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // Check to see that all of the elements to operate on are strings
+ if (dynamic_cast<const type::String*>(e.left_get().type_get()) == nullptr
+ || dynamic_cast<const type::String*>(e.right_get().type_get()) == nullptr)
+ {
+ return super_type::operator()(e);
+ }
+
+ const auto left = recurse(e.left_get());
+ const auto right = recurse(e.right_get());
+
+ misc::variant<ast::Exp*, ast::ChunkList*> res;
+
+ switch (e.oper_get())
+ {
+ case ast::OpExp::Oper::eq:
+ {
+ res = parse::parse(parse::Tweast() << "streq(" << left << ", " << right << ") = 0");
+ break;
+ }
+ case ast::OpExp::Oper::ne:
+ {
+ res = parse::parse(parse::Tweast() << "streq(" << left << ", " << right << ") <> 0");
+ break;
+ }
+ case ast::OpExp::Oper::lt:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") = -1");
+ break;
+ }
+ case ast::OpExp::Oper::le:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") <= 0");
+ break;
+ }
+ case ast::OpExp::Oper::gt:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") = 1");
+ break;
+ }
+ case ast::OpExp::Oper::ge:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") >= 0");
+ break;
+ }
+ default:
+ break;
+ }
+
+ ast::Exp* final = std::get<ast::Exp*>(res);
+ result_ = final;
+ }
+
+ /*----------------------.
+ | Desugar `for' loops. |
+ `----------------------*/
+
+ /*<<-
+ Desugar `for' loops as `while' loops:
+
+ for i := lo to hi do
+ body
+
+ is transformed as:
+
+ let
+ var _lo := lo
+ var _hi := hi
+ var i := _lo
+ in
+ if i <= _hi then
+ while 1 do
+ (
+ body;
+ if i = _hi then
+ break;
+ i := i + 1
+ )
+ end
+
+ Notice that:
+
+ - a `_hi' variable is introduced so that `hi' is evaluated only
+ once;
+
+ - a `_lo' variable is introduced to prevent `i' from being in the
+ scope of `_hi';
+
+ - a first test is performed before entering the loop, so that the
+ loop condition becomes `i < _hi' (instead of `i <= _hi'); this
+ is done to prevent overflows on INT_MAX.
+ ->>*/
+
+ void DesugarVisitor::operator()(const ast::ForExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ auto var_init = recurse(e.vardec_get().init_get());
+ auto lim = recurse(e.hi_get());
+ auto body = recurse(e.body_get());
+ auto iterator = e.vardec_get().name_get();
+ auto res = parse::parse(parse::Tweast() << "let "
+ "var _lo := " << var_init <<
+ " var _hi := " << lim <<
+ " var " << iterator << " := _lo "
+ "in "
+ "if " << iterator << " <= _hi then "
+ "while 1 do "
+ "( " << body << ";"
+ "if " << iterator << " = _hi then "
+ "break;"
+ << iterator << " := " << iterator << " + 1 "
+ ") "
+ "end");
+ ast::Exp* final = std::get<ast::Exp*>(res);
+ result_ = final;
+ }
+
+} // namespace desugar