summaryrefslogtreecommitdiff
path: root/tiger-compiler/src/object/binder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tiger-compiler/src/object/binder.cc')
-rw-r--r--tiger-compiler/src/object/binder.cc176
1 files changed, 176 insertions, 0 deletions
diff --git a/tiger-compiler/src/object/binder.cc b/tiger-compiler/src/object/binder.cc
new file mode 100644
index 0000000..8220da5
--- /dev/null
+++ b/tiger-compiler/src/object/binder.cc
@@ -0,0 +1,176 @@
+/**
+ ** \file object/binder.cc
+ ** \brief Implementation of object::Binder.
+ */
+
+#include <ast/all.hh>
+#include <object/binder.hh>
+
+namespace object
+{
+ /*---------.
+ | Visits. |
+ `---------*/
+
+ /* Handle the case of `self'. If the variable is not named `self', handle it
+ like the normal `Binder'. If it is `self', it must be bound to a definiton
+ site, unless:
+ * it is inside a method,
+ * AND `self` is not overridden.
+ If those conditions are met, `self' is an implicitly defined instance of
+ the class.
+
+ Variable `self' will have a meaningful definition after the object
+ constructs have been desugared. */
+
+ void Binder::operator()(ast::SimpleVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ misc::symbol test_self("self");
+ if (e.name_get() == test_self && within_method_dec_ && !overrided_self_)
+ {
+ e.def_set(nullptr);
+ }
+ else
+ {
+ super_type::operator()(e);
+ }
+ }
+
+ // Handle the case of `Object'.
+ void Binder::operator()(ast::NameTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ misc::symbol test_obj("Object");
+ if (e.name_get() == test_obj)
+ {
+ e.def_set(nullptr);
+ }
+ else
+ {
+ super_type::operator()(e);
+ }
+ }
+
+ /*---------------.
+ | Visiting Exp. |
+ `---------------*/
+
+ void Binder::operator()(ast::ForExp& e)
+ {
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ super_type::operator()(e);
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ /*-------------------.
+ | Visiting ClassTy. |
+ `-------------------*/
+
+ void Binder::operator()(ast::ClassTy& e)
+ {
+ // FIXME DONE: Some code was deleted here (Scope begins).
+ begin_scope();
+ e.super_get().accept(*this);
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = true;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = false;
+ e.chunks_get().accept(*this);
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ // FIXME DONE: Some code was deleted here (Scope ends).
+ end_scope();
+ }
+
+ /*---------------.
+ | Visiting Dec. |
+ `---------------*/
+
+ void Binder::operator()(ast::VarDec& e)
+ {
+ if (within_class_ty_)
+ {
+ within_class_ty_ = false;
+ // Don't bind class attributes.
+ super_type::super_type::operator()(e);
+ within_class_ty_ = true;
+ }
+ else
+ {
+ // But still bind other variable declarations.
+ super_type::operator()(e);
+ if (e.name_get() == "self" && within_method_dec_)
+ overrided_self_ = true;
+ }
+ }
+
+ void Binder::operator()(ast::FunctionChunk& e)
+ {
+ chunk_visit<ast::FunctionDec>(e);
+ }
+
+ template <class D> void Binder::chunk_visit(ast::Chunk<D>& e)
+ {
+ // Shorthand.
+ using chunk_type = ast::Chunk<D>;
+ // FIXME: Some code was deleted here (Two passes: once on headers, then on bodies).
+ for (auto machala : e)
+ {
+ if (dynamic_cast<ast::MethodDec*>(machala))
+ {
+ scoped_map_fun_.put(machala->name_get(), machala);
+ }
+ }
+ super_type::operator()(e);
+ }
+
+ // This trampoline is needed, since `virtual' and `template' cannot
+ // be mixed.
+ template <>
+ void Binder::visit_dec_header<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ // FIXME DONE: Some code was deleted here (Call the super type).
+ super_type::operator()(e);
+ }
+
+ // Compute the bindings of this function's body.
+ template <> void Binder::visit_dec_body<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = false;
+ // FIXME DONE: Some code was deleted here (Call the super type).
+ super_type::operator()(e);
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ /* We can't bind methods definitions without types, so we don't
+ store them. Nonetheless, object::Binder must still recurse
+ through the children of ast::MethodChunk to bind other names.
+
+ Note that as we defer the binding of methods to the
+ type-checkimg, there is no need to visit method in two-pass (like
+ bind::Binder does for functions for instance). */
+ void Binder::operator()(ast::MethodDec& e)
+ {
+ // FIXME DONE: Some code was deleted here (Scope begins).
+ begin_scope();
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = true;
+ bool saved_overrided_self = overrided_self_;
+ overrided_self_ = false;
+ ast::DefaultVisitor::operator()(static_cast<ast::FunctionDec&>(e));
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ overrided_self_ = saved_overrided_self;
+ // FIXME DONE: Some code was deleted here (Scope ends).
+ end_scope();
+ }
+
+} // namespace object