diff --git a/compiler2/Setting.hh b/compiler2/Setting.hh
index 74d0029ac70bcaa9f7fc6b87950fb1c81d06cbfd..dc5d47af2568ea60cce8bf7edd0124cd0d4b310c 100644
--- a/compiler2/Setting.hh
+++ b/compiler2/Setting.hh
@@ -728,6 +728,12 @@ public:
    * scope-hierarchy) than a Module.
    */
   class Ref_simple : public Reference {
+  public:
+    enum reftype_t {
+      REF_BASIC, // basic reference (not class related to any class scope)
+      REF_SUPER, // reference to the superclass
+      REF_THIS   // reference to the current class object
+    };
   protected: // Derived classes need access
     /** Points to the referred assignment. Used for caching. */
     Assignment *refd_ass;
@@ -743,6 +749,8 @@ public:
     /** Returns the \a id. */
     virtual const Identifier* get_id() =0;
     /** Creates a display-name for the reference. */
+    virtual reftype_t get_reftype() const { return REF_BASIC; }
+    virtual void set_reftype(reftype_t) { FATAL_ERROR("Ref_simple::set_reftype"); }
     virtual string get_dispname();
     virtual Setting* get_refd_setting();
     /** \param check_parlist is ignored */
diff --git a/compiler2/Type.cc b/compiler2/Type.cc
index 3281174edf41758ff4813604c0e61200a4099fb1..19f5f90d64ec58683c9823cdff13271c3bcf71ea 100644
--- a/compiler2/Type.cc
+++ b/compiler2/Type.cc
@@ -1677,7 +1677,7 @@ namespace Common {
 
   Type *Type::get_field_type(Ttcn::FieldOrArrayRefs *subrefs,
     expected_value_t expected_index, ReferenceChain *refch,
-    bool interrupt_if_optional)
+    bool interrupt_if_optional, Assignment** last_method)
   {
     if (!subrefs) return this;
     Type *t = this;
@@ -1789,11 +1789,15 @@ namespace Common {
           return 0;
         case Assignment::A_FUNCTION:
         case Assignment::A_EXT_FUNCTION:
-          // TODO: are these handled elsewhere? in some kind of statement?
-          ref->error("Invalid reference to method `%s' with no return type in "
-            "class type `%s'",
-            id.get_dispname().c_str(), t->get_typename().c_str());
-          return 0;
+          if (i != nof_refs - 1 || last_method == NULL) {
+            ref->error("Invalid reference to method `%s' with no return type in "
+              "class type `%s'",
+              id.get_dispname().c_str(), t->get_typename().c_str());
+            return 0;
+          }
+          // a method with no return value can still be valid (e.g. if it's
+          // in a statement)
+          // proceed as normal and return null at the end
         case Assignment::A_FUNCTION_RVAL:
         case Assignment::A_FUNCTION_RTEMP:
         case Assignment::A_EXT_FUNCTION_RVAL:
@@ -1817,6 +1821,9 @@ namespace Common {
             ap_list->set_my_scope(parsed_pars->get_my_scope());
             ref->set_actual_par_list(ap_list);
           }
+          if (last_method != NULL) {
+            *last_method = ass;
+          }
           break; }
         default:
           FATAL_ERROR("Type::get_field_type - %s shouldn't be in a class",
diff --git a/compiler2/Type.hh b/compiler2/Type.hh
index 547c03cfb200b1cc133fe1b96ecac129b48c716c..f3423ab861f2455ae7d3358058cb90dc966de83d 100644
--- a/compiler2/Type.hh
+++ b/compiler2/Type.hh
@@ -634,10 +634,15 @@ namespace Common {
      * Special case: if \a interrupt_if_optional is true then return NULL if an
      * optional field has been reached. Using this bool parameter it can be
      * checked if a referenced field is on an optional path (used by template
-     * restriction checking code) */
+     * restriction checking code)
+     * @param last_method if not null, indicates that a method with no return
+     * value is valid at the end of the subreferences, and should not produce
+     * an error; the function assignment is also stored in the pointer pointed
+     * to by this parameter if the last subreference is a method (even if it has
+     * a return value) */
     Type *get_field_type(Ttcn::FieldOrArrayRefs *subrefs,
       expected_value_t expected_index, ReferenceChain *refch = 0,
-      bool interrupt_if_optional = false);
+      bool interrupt_if_optional = false, Assignment** last_method = NULL);
     /** subrefs must point to an existing field, get_field_type() should be used
       * to check. subrefs_array will be filled with the indexes of the fields,
       * type_array will be filled with types whose field indexes were collected,
@@ -1003,6 +1008,7 @@ namespace Common {
       expected_value_t expected_value, namedbool incomplete_allowed);
     void chk_this_value_Component(Value *value);
     void chk_this_value_FAT(Value *value);
+    void chk_this_value_class(Value* value);
   public:
     /** Checks whether template \a t is a specific value and the embedded value
      * is a referenced one. If the reference in the value points to a
@@ -1300,7 +1306,7 @@ namespace Common {
     void generate_code_ispresentboundchosen(expression_struct *expr,
       Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
       const string& global_id, const string& external_id,
-      const bool is_template, const namedbool optype, const char* field);
+      bool is_template, const namedbool optype, const char* field);
 
     /** Extension attribute for optimized code generation of structured types:
      *    with { extension "optimize:xxx" }
diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc
index ab219c6101e5a151a7f26e5699a2b93077a1660e..80ccc86a30a3be317188c322840eae2610da5e3b 100644
--- a/compiler2/Type_chk.cc
+++ b/compiler2/Type_chk.cc
@@ -4131,6 +4131,9 @@ bool Type::chk_this_value(Value *value, Common::Assignment *lhs, expected_value_
   case T_TESTCASE:
     chk_this_value_FAT(value);
     break;
+  case T_CLASS:
+    chk_this_value_class(value);
+    break;
   default:
     FATAL_ERROR("Type::chk_this_value()");
   } // switch
@@ -4194,6 +4197,15 @@ bool Type::chk_this_refd_value(Value *value, Common::Assignment *lhs, expected_v
       error_flag = true;
     }
     break;
+  case Assignment::A_TYPE:
+    if (ass->get_Type()->get_type_refd_last()->typetype != T_CLASS) {
+      value->error("Reference to a %s was expected instead of %s",
+        expected_value == EXPECTED_TEMPLATE ? "value or template" : "value",
+        ass->get_description().c_str());
+      value->set_valuetype(Value::V_ERROR);
+      return self_ref;
+    }
+    // else fall through
   case Assignment::A_VAR:
   case Assignment::A_PAR_VAL:
   case Assignment::A_PAR_VAL_IN:
@@ -5975,6 +5987,31 @@ void Type::chk_this_value_FAT(Value *value)
   }
 }
 
+void Type::chk_this_value_class(Value* value)
+{
+  Value* v = value->get_value_refd_last();
+  switch(v->get_valuetype()) {
+  case Value::V_TTCN3_NULL:
+    break; // OK
+  case Value::V_REFD:
+    // TODO
+    break;
+  case Value::V_EXPR:
+    switch (v->get_optype()) {
+    case Value::OPTYPE_CLASS_CREATE:
+      // TODO
+      break;
+    default:
+      // error
+      break;
+    }
+    break;
+  default:
+    // error
+    break;
+  }
+}
+
 void Type::chk_this_template_length_restriction(Template *t)
 {
   Ttcn::LengthRestriction *lr = t->get_length_restriction();
@@ -6108,6 +6145,40 @@ void Type::chk_this_template_ref(Template *t)
     // endless recursion in case of embedded circular references.
     // The parameter lists will be verified later.
     Assignment *ass = v->get_reference()->get_refd_assignment(false);
+    if (ass != NULL && ass->get_asstype() == Assignment::A_VAR) {
+      // there could be class objects in the subreferences, which would change
+      // the type of the assignment (e.g. to a var template);
+      // use the assignment after the last class object in the subreference chain
+      Ttcn::FieldOrArrayRefs* subrefs = v->get_reference()->get_subrefs();
+      if (subrefs != NULL) {
+        Type* type = ass->get_Type();
+        if (type->get_field_type(subrefs, EXPECTED_DYNAMIC_VALUE) != NULL) {
+          // subrefs are valid
+          for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) {
+            type = type->get_type_refd_last();
+            Ttcn::FieldOrArrayRef* subref = subrefs->get_ref(i);
+            switch (subref->get_type()) {
+            case Ttcn::FieldOrArrayRef::FIELD_REF:
+            case Ttcn::FieldOrArrayRef::FUNCTION_REF:
+              if (type->typetype == T_CLASS) {
+                ass = type->get_class_type_body()->
+                  get_local_ass_byId(*subref->get_id());
+                type = ass->get_Type();
+              }
+              else {
+                type = type->get_comp_byName(*subref->get_id())->get_type();
+              }
+              break;
+            case Ttcn::FieldOrArrayRef::ARRAY_REF:
+              if (type->is_structured_type()) {
+                type = type->get_ofType();
+              }
+              break;
+            }
+          }
+        }
+      }
+    }
     if (ass) {
       switch (ass->get_asstype()) {
       case Assignment::A_VAR_TEMPLATE: {
diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc
index 04bc4ae680f62933272415027f4ebee1a7509252..7ef873ec3c3e91d37c90e0b2ab111dc9b6e75528 100644
--- a/compiler2/Type_codegen.cc
+++ b/compiler2/Type_codegen.cc
@@ -2893,7 +2893,6 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
     Ttcn::FieldOrArrayRef *ref = subrefs->get_ref(i);
     switch (ref->get_type()) {
     case Ttcn::FieldOrArrayRef::FIELD_REF: {
-      CompField* cf = t->get_comp_byName(*ref->get_id());
       switch (t->typetype) {
       case T_CHOICE_T:
       case T_CHOICE_A:
@@ -2903,13 +2902,17 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
       case T_SEQ_T:
       case T_SET_T:
       case T_SEQ_A:
-      case T_SET_A:
+      case T_SET_A: {
+        CompField* cf = t->get_comp_byName(*ref->get_id());
         if (cf->get_is_optional()) return FALSE;
+        t = cf->get_type();
+        break; }
+      case T_CLASS:
+        t = t->get_class_type_body()->get_local_ass_byId(*ref->get_id())->get_Type();
         break;
       default:
         FATAL_ERROR("Type::ispresent_anyvalue_embedded_field()");
       }
-      t = cf->get_type();
     } break;
     case Ttcn::FieldOrArrayRef::ARRAY_REF:
       switch (t->typetype) {
@@ -2932,7 +2935,7 @@ bool Type::ispresent_anyvalue_embedded_field(Type* t,
 
 void Type::generate_code_ispresentboundchosen(expression_struct *expr,
     Ttcn::FieldOrArrayRefs *subrefs, Common::Module* module,
-    const string& global_id, const string& external_id, const bool is_template,
+    const string& global_id, const string& external_id, bool is_template,
     const namedbool optype, const char* field)
 {
   if (!subrefs) return;
@@ -2950,7 +2953,9 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
     // (e.g. because of circular reference)
     if (t->typetype == T_ERROR) return;
 
-    if (is_template) {
+    if (is_template && t->typetype != T_CLASS) {
+      // TODO: the initial value of 'is_template' is not always set properly
+      // (it seems to always be false in case of functions)
       bool anyval_ret_val = TRUE;
       if (optype == ISPRESENT) {
         anyval_ret_val = ispresent_anyvalue_embedded_field(t, subrefs, i);
@@ -2987,9 +2992,23 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
     switch (ref->get_type()) {
     case Ttcn::FieldOrArrayRef::FIELD_REF: {
       const Identifier& id = *ref->get_id();
-      CompField* cf = t->get_comp_byName(id);
-      next_t = cf->get_type();
-      next_o = !is_template && cf->get_is_optional();
+      if (t->typetype == T_CLASS) {
+        Assignment* ass = t->get_class_type_body()->get_local_ass_byId(id);
+        if (ass->get_asstype() == Assignment::A_TEMPLATE ||
+            ass->get_asstype() == Assignment::A_VAR_TEMPLATE) {
+          is_template = true;
+        }
+        else {
+          is_template = false;
+        }
+        next_t = ass->get_Type();
+        next_o = false;
+      }
+      else {
+        CompField* cf = t->get_comp_byName(id);
+        next_t = cf->get_type();
+        next_o = !is_template && cf->get_is_optional();
+      }
 
       switch (t->typetype) {
       case T_CHOICE_A:
@@ -3008,6 +3027,7 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
       case T_SET_A:
       case T_SET_T:
       case T_ANYTYPE:
+      case T_CLASS:
         break;
       default:
         FATAL_ERROR("Type::generate_code_ispresentboundchosen()");
@@ -3125,21 +3145,29 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
         const char *tmp_id_str = tmp_id.c_str();
         const char *tmp_id2_str = tmp_id2.c_str();
         
-        // Own const ref to the temp value
-        expr->expr = mputprintf(expr->expr,
-          "const %s%s& %s = %s;\n",
-          t->get_genname_value(module).c_str(),
-          is_template ? "_template" : "",
-          tmp_id_str, tmp_generalid_str);
-        // Get the const ref of the field from the previous const ref
-        // If we would get the const ref of the field immediately then the
-        // value in the const ref would be free-d instantly.
-        expr->expr = mputprintf(expr->expr,
-          "const %s%s& %s = %s.%s%s();\n",
-          next_t->get_genname_value(module).c_str(),
-          is_template ? "_template" : "",
-          tmp_id2_str, tmp_id_str,
-          t->typetype == T_ANYTYPE ? "AT_" : "", id.get_name().c_str());
+        if (t->typetype == T_CLASS) {
+          expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s;\n",
+            next_t->get_genname_value(module).c_str(),
+            is_template ? "_template" : "", tmp_id2_str,
+            tmp_generalid_str, id.get_name().c_str());
+        }
+        else {
+          // Own const ref to the temp value
+          expr->expr = mputprintf(expr->expr,
+            "const %s%s& %s = %s;\n",
+            t->get_genname_value(module).c_str(),
+            is_template ? "_template" : "",
+            tmp_id_str, tmp_generalid_str);
+          // Get the const ref of the field from the previous const ref
+          // If we would get the const ref of the field immediately then the
+          // value in the const ref would be free-d instantly.
+          expr->expr = mputprintf(expr->expr,
+            "const %s%s& %s = %s.%s%s();\n",
+            next_t->get_genname_value(module).c_str(),
+            is_template ? "_template" : "",
+            tmp_id2_str, tmp_id_str,
+            t->typetype == T_ANYTYPE ? "AT_" : "", id.get_name().c_str());
+        }
 
         if (i != nof_refs - 1 || optype == ISCHOSEN) {
           expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
@@ -3174,6 +3202,68 @@ void Type::generate_code_ispresentboundchosen(expression_struct *expr,
         tmp_generalid_str = mcopystr(tmp_id2_str);
       }
 
+      t = next_t;
+      break; }
+    case Ttcn::FieldOrArrayRef::FUNCTION_REF: {
+      const Identifier& id = *ref->get_id();
+      Assignment* ass = t->get_class_type_body()->get_local_ass_byId(id);
+      if (ass->get_asstype() == Assignment::A_FUNCTION_RTEMP ||
+          ass->get_asstype() == Assignment::A_EXT_FUNCTION_RTEMP) {
+        is_template = true;
+      }
+      else {
+        is_template = false;
+      }
+      Ttcn::Def_Function_Base* def_func = dynamic_cast<Ttcn::Def_Function_Base*>(ass);
+      next_t = def_func->get_return_type();
+      
+      expr->expr = mputprintf(expr->expr, "if(%s) {\n", global_id.c_str());
+      expstring_t closing_brackets2 = mprintf("}\n%s", closing_brackets);
+      Free(closing_brackets);
+      closing_brackets = closing_brackets2;
+
+      const string& tmp_id = module->get_temporary_id();
+      const char *tmp_id_str = tmp_id.c_str();
+      
+      expr->expr = mputprintf(expr->expr, "const %s%s %s = %s->%s(",
+        next_t->get_genname_value(module).c_str(),
+        is_template ? "_template" : "", tmp_id_str,
+        tmp_generalid_str, id.get_name().c_str());
+      ref->get_actual_par_list()->generate_code_noalias(expr, ass->get_FormalParList());
+      expr->expr = mputstr(expr->expr, ");\n");
+
+      if (i != nof_refs - 1 || optype == ISCHOSEN) {
+        expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
+          global_id.c_str(), tmp_id_str);
+      }
+      if (i == nof_refs - 1) {
+        switch (optype) {
+        case ISBOUND:
+          expr->expr = mputprintf(expr->expr, "%s = %s.is_bound();\n",
+            global_id.c_str(), tmp_id_str);
+          break;
+        case ISPRESENT:
+          expr->expr = mputprintf(expr->expr, "%s = %s.is_present(%s);\n",
+            global_id.c_str(), tmp_id_str,
+            (is_template && omit_in_value_list) ? "TRUE" : "");
+          break;
+        case ISCHOSEN:
+          expr->expr = mputprintf(expr->expr,
+            "if (%s) {\n"
+            "%s = %s.ischosen(%s);\n"
+            "}\n", global_id.c_str(), global_id.c_str(), tmp_id_str, field);
+          break;
+        case ISVALUE:
+          expr->expr = mputprintf(expr->expr, "%s = %s.is_value();\n",
+            global_id.c_str(), tmp_id_str);
+          break;
+        default:
+          FATAL_ERROR("Type::generate_code_ispresentboundchosen");
+        }
+      }
+      Free(tmp_generalid_str);
+      tmp_generalid_str = mcopystr(tmp_id_str);
+
       t = next_t;
       break; }
     case Ttcn::FieldOrArrayRef::ARRAY_REF: {
diff --git a/compiler2/Value.cc b/compiler2/Value.cc
index 6817d7d62aaa618fa6e07807280dae23116dddea..2cee16d5b2e0cf423697c20b02911477b76b5c0d 100644
--- a/compiler2/Value.cc
+++ b/compiler2/Value.cc
@@ -4060,6 +4060,12 @@ namespace Common {
 	  exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
 	  ass->get_description().c_str());
         goto error;
+      case Assignment::A_TYPE:
+        if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
+          tmp_type = ass->get_Type();
+          break;
+        }
+        // else fall through
       default:
         error("Reference to a %s was expected instead of %s",
 	  exp_val == Type::EXPECTED_TEMPLATE ? "value or template" : "value",
@@ -9536,22 +9542,27 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
               destroy_refch = true;
             }
             if (refch->add(get_fullname())) {
-              Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs();
-              Value *v_refd = ass->get_Value()
-              ->get_refd_sub_value(subrefs, 0,
-                  u.ref.ref->getUsedInIsbound(), refch);
-              if (v_refd) {
-                Value *v_last = v_refd->get_value_refd_last(refch);
-                // in case of circular recursion the valuetype is already set
-                // to V_ERROR, so don't set the cache
-                if (valuetype == V_REFD) u.ref.refd_last = v_last;
-              } else if (subrefs && subrefs->has_unfoldable_index()) {
+              if (ass->get_my_scope()->get_parent_scope()->is_class_scope()) {
                 u.ref.refd_last = this;
-              } else if (u.ref.ref->getUsedInIsbound()) {
-                u.ref.refd_last = this;
-              } else {
-                // the sub-reference points to a non-existent field
-                set_valuetype(V_ERROR);
+              }
+              else {
+                Ttcn::FieldOrArrayRefs *subrefs = u.ref.ref->get_subrefs();
+                Value *v_refd = ass->get_Value()
+                ->get_refd_sub_value(subrefs, 0,
+                    u.ref.ref->getUsedInIsbound(), refch);
+                if (v_refd) {
+                  Value *v_last = v_refd->get_value_refd_last(refch);
+                  // in case of circular recursion the valuetype is already set
+                  // to V_ERROR, so don't set the cache
+                  if (valuetype == V_REFD) u.ref.refd_last = v_last;
+                } else if (subrefs && subrefs->has_unfoldable_index()) {
+                  u.ref.refd_last = this;
+                } else if (u.ref.ref->getUsedInIsbound()) {
+                  u.ref.refd_last = this;
+                } else {
+                  // the sub-reference points to a non-existent field
+                  set_valuetype(V_ERROR);
+                }
               }
             } else {
               // a circular recursion was detected
@@ -9585,6 +9596,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
               ass->get_description().c_str());
             set_valuetype(V_ERROR);
             break;
+          case Assignment::A_TYPE:
+            if (ass->get_Type()->get_type_refd_last()->get_typetype() == Type::T_CLASS) {
+              u.ref.refd_last = this;
+              break;
+            }
+            // else fall through
           default:
             u.ref.ref->error("Reference to a value was expected instead of %s",
               ass->get_description().c_str());
@@ -9641,12 +9658,12 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
     case V_OPENTYPE:
     case V_UNDEF_LOWERID:
     case V_UNDEF_BLOCK:
-    case V_TTCN3_NULL:
     case V_REFER:
       // these value types are eliminated during semantic analysis
       FATAL_ERROR("Value::is_unfoldable()");
     case V_ERROR:
     case V_INVOKE:
+    case V_TTCN3_NULL:
       return true;
     case V_CHOICE:
       return u.choice.alt_value->is_unfoldable(refch, exp_val);
@@ -12911,7 +12928,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
   void Value::generate_code_expr_mandatory(expression_struct *expr)
   {
     generate_code_expr(expr);
-    if (valuetype == V_REFD && get_value_refd_last()->valuetype == V_REFD)
+    if (valuetype == V_REFD && get_value_refd_last()->valuetype == V_REFD &&
+        u.ref.ref->get_refd_assignment()->get_Type()->get_type_refd_last()->get_typetype() != Type::T_CLASS)
       generate_code_expr_optional_field_ref(expr, u.ref.ref);
   }
 
@@ -13641,6 +13659,7 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
     case OPTYPE_ISBOUND: {
       Template::templatetype_t temp = u.expr.ti1->get_Template()
           ->get_templatetype();
+      // TODO: use get_refd_assignment instead to determine whether it's a template?
       if (temp == Template::SPECIFIC_VALUE) {
         Value* specific_value = u.expr.ti1->get_Template()
             ->get_specific_value();
@@ -15542,6 +15561,8 @@ void Value::chk_expr_operand_execute_refd(Value *v1,
     case V_ALTSTEP:
     case V_TESTCASE:
       return get_single_expr_fat();
+    case V_TTCN3_NULL:
+      return string("NULL_VALUE");
     default:
       FATAL_ERROR("Value::get_single_expr()");
       return string();
diff --git a/compiler2/Value.hh b/compiler2/Value.hh
index 94f11c021aa0f056d118d6fbb013915e2d9b4ff0..0581f6f69751538909d4cede5b29853772796212 100644
--- a/compiler2/Value.hh
+++ b/compiler2/Value.hh
@@ -116,7 +116,7 @@ namespace Common {
       V_UNDEF_BLOCK, /**< undefined {block} */
       V_OMIT, /**< special value for optional values */
       V_VERDICT, /**< verdict */
-      V_TTCN3_NULL, /**< TTCN-3 null (for component or default references) */
+      V_TTCN3_NULL, /**< TTCN-3 null (for component, default or class references) */
       V_DEFAULT_NULL, /**< null default reference */
       V_FAT_NULL, /**< null for function, altstep and testcase */
       V_EXPR, /**< expressions */
diff --git a/compiler2/ttcn3/AST_ttcn3.cc b/compiler2/ttcn3/AST_ttcn3.cc
index 6949d1c8af514a198aec3f3d571debed96591fee..544787f2383e91bde1cdb7a915ecc75c00f021ff 100644
--- a/compiler2/ttcn3/AST_ttcn3.cc
+++ b/compiler2/ttcn3/AST_ttcn3.cc
@@ -430,11 +430,7 @@ namespace Ttcn {
                                        bool const_ref, /* = false */
                                        bool is_template, /* = false */
                                        size_t nof_subrefs /* = UINT_MAX */)
-  {
-    // ensure everything is checked
-    // TODO: incorporate this into the semantic analysis somehow...
-    if (type) type->get_field_type(this, Common::Type::EXPECTED_DYNAMIC_VALUE);
-    
+  {    
     size_t n_refs = (nof_subrefs != UINT_MAX) ? nof_subrefs : refs.size();
     for (size_t i = 0; i < n_refs; i++) {
       if (type) type = type->get_type_refd_last();
@@ -691,21 +687,31 @@ namespace Ttcn {
   // =================================
   
   Reference::Reference(const Reference& p)
-    : Ref_base(p), parlist(NULL), gen_const_prefix(false), expr_cache(NULL)
+    : Ref_base(p), reftype(p.reftype), parlist(NULL), gen_const_prefix(false),
+    expr_cache(NULL)
   {
     params = p.params != NULL ? p.params->clone() : NULL;
   }
 
   Reference::Reference(Identifier *p_id)
-    : Ref_base(), parlist(NULL), params(NULL), gen_const_prefix(false),
-    expr_cache(NULL)
+    : Ref_base(), reftype(REF_BASIC), parlist(NULL), params(NULL),
+    gen_const_prefix(false), expr_cache(NULL)
   {
     subrefs.add(new FieldOrArrayRef(p_id));
   }
   
+  Reference::Reference(reftype_t p_reftype)
+  : Ref_base(), reftype(p_reftype), parlist(NULL), params(NULL),
+    gen_const_prefix(false), expr_cache(NULL)
+  {
+    if (reftype != REF_THIS) {
+      FATAL_ERROR("Ttcn::Reference(): basic or 'super' reference with no ID");
+    }
+  }
+  
   Reference::Reference(Identifier *p_modid, Identifier *p_id,
-                       ParsedActualParameters *p_params)
-    : Ref_base(p_modid, p_id), parlist(NULL), params(p_params),
+                       ParsedActualParameters *p_params, reftype_t p_reftype)
+    : Ref_base(p_modid, p_id), reftype(p_reftype), parlist(NULL), params(p_params),
     gen_const_prefix(false), expr_cache(NULL)
   {
     if (p_params == NULL) {
@@ -1043,6 +1049,21 @@ namespace Ttcn {
     ref_usage_found();
     Common::Assignment *ass = get_refd_assignment();
     if (!ass) FATAL_ERROR("Reference::generate_code()");
+    if (reftype == REF_THIS) {
+      if (id != NULL) {
+        expr->expr = mputstr(expr->expr, "this->");
+      }
+      else { // no 'id' means it's just a 'this' reference
+        expr->expr = mputprintf(expr->expr, "OBJECT_REF<%s>(this)",
+          ass->get_Type()->get_genname_value(my_scope).c_str());
+        return;
+      }
+    }
+    else if (reftype == REF_SUPER) {
+      expr->expr = mputprintf(expr->expr, "%s::",
+        my_scope->get_scope_class()->get_base_type()->
+        get_genname_value(my_scope).c_str());
+    }
     string const_prefix; // empty by default
     if (gen_const_prefix) {
       if (ass->get_asstype() == Common::Assignment::A_CONST) {
@@ -1053,8 +1074,6 @@ namespace Ttcn {
       }
     }
     if (parlist != NULL) {
-      // reference without parameters to a template that has only default formal parameters.
-      // if @lazy: nothing to do, it's a C++ function call just like in case of Ref_pard::generate_code()
       expr->expr = mputprintf(expr->expr, "%s(",
         ass->get_genname_from_scope(my_scope).c_str());
       parlist->generate_code_alias(expr, ass->get_FormalParList(),
@@ -1208,9 +1227,16 @@ namespace Ttcn {
       
       expression_struct isbound_expr;
       Code::init_expr(&isbound_expr);
-      isbound_expr.preamble = mputprintf(isbound_expr.preamble,
+      if (ass->get_Type()->get_type_refd_last()->get_typetype() == Common::Type::T_CLASS) {
+        isbound_expr.preamble = mputprintf(isbound_expr.preamble,
+          "boolean %s = %s != NULL_VALUE;\n", tmp_generalid_str,
+          ass_id_str);
+      }
+      else {
+        isbound_expr.preamble = mputprintf(isbound_expr.preamble,
           "boolean %s = %s.is_bound();\n", tmp_generalid_str,
           ass_id_str);
+      }
       namedbool p_optype;
       if (optype == Value::OPTYPE_ISBOUND) {
         p_optype = ISBOUND;
@@ -1268,7 +1294,7 @@ namespace Ttcn {
   void Reference::detect_modid()
   {
     // do nothing if detection is already performed
-    if (id) return;
+    if (id || reftype == REF_THIS) return;
     // the first element of subrefs must be an <id>
     const Identifier *first_id = subrefs.get_ref(0)->get_id(), *second_id = 0;
     const ParsedActualParameters* second_params = 0;
@@ -2177,14 +2203,16 @@ namespace Ttcn {
         ass_m.add(name, def);
         if (parent_scope) {
           if (parent_scope->has_ass_withId(id)) {
-            const char *dispname_str = id.get_dispname().c_str();
-            def->error("Definition with identifier `%s' is not unique in the "
-              "scope hierarchy", dispname_str);
-            Reference ref(0, id.clone());
-            Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref);
-            if (!ass) FATAL_ERROR("OtherDefinitions::chk_for()");
-            ass->note("Previous definition with identifier `%s' in higher "
-              "scope unit is here", dispname_str);
+            if (parent_scope->get_scope_class() == NULL) {
+              const char *dispname_str = id.get_dispname().c_str();
+              def->error("Definition with identifier `%s' is not unique in the "
+                "scope hierarchy", dispname_str);
+              Reference ref(0, id.clone());
+              Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref);
+              if (!ass) FATAL_ERROR("OtherDefinitions::chk_for()");
+              ass->note("Previous definition with identifier `%s' in higher "
+                "scope unit is here", dispname_str);
+            }
           } else if (parent_scope->is_valid_moduleid(id)) {
             def->warning("Definition with name `%s' hides a module identifier",
               id.get_dispname().c_str());
@@ -2608,6 +2636,11 @@ namespace Ttcn {
 
   Common::Assignment* Module::get_ass_bySRef(Ref_simple *p_ref)
   {
+    if (p_ref->get_reftype() != Ref_simple::REF_BASIC) {
+      p_ref->error("Reference to `%s' can only be used inside a class definition",
+        p_ref->get_reftype() == Ref_simple::REF_THIS ? "this" : "super");
+      return NULL;
+    }
     const Identifier *r_modid = p_ref->get_modid();
     const Identifier *r_id = p_ref->get_id();
     if (r_modid) {
@@ -9834,7 +9867,9 @@ namespace Ttcn {
   Common::Assignment *FormalParList::get_ass_bySRef(Common::Ref_simple *p_ref)
   {
     if (!p_ref || !checked) FATAL_ERROR("FormalParList::get_ass_bySRef()");
-    if (p_ref->get_modid()) return parent_scope->get_ass_bySRef(p_ref);
+    if (p_ref->get_modid() || p_ref->get_reftype() != Ref_simple::REF_BASIC) {
+      return parent_scope->get_ass_bySRef(p_ref);
+    }
     else {
       const string& name = p_ref->get_id()->get_name();
       if (pars_m.has_key(name)) return pars_m[name];
@@ -9900,7 +9935,8 @@ namespace Ttcn {
         pars_m[name]->note("Previous definition of `%s' is here", dispname);
       } else {
         pars_m.add(name, par);
-        if (parent_scope && parent_scope->has_ass_withId(id)) {
+        if (parent_scope && parent_scope->get_scope_class() == NULL &&
+            parent_scope->has_ass_withId(id)) {
           par->error("Parameter name `%s' is not unique in the scope "
             "hierarchy", dispname);
           Reference ref(0, id.clone());
diff --git a/compiler2/ttcn3/AST_ttcn3.hh b/compiler2/ttcn3/AST_ttcn3.hh
index 24435f66f154a67c1fc710a2d155c16893e473f9..695ddf5e37883f8b365e40a8c0ee6d578679dcf6 100644
--- a/compiler2/ttcn3/AST_ttcn3.hh
+++ b/compiler2/ttcn3/AST_ttcn3.hh
@@ -334,11 +334,12 @@ namespace Ttcn {
   };
 
   /**
-   * TTCN-3 reference without parameters.
+   * TTCN-3 reference.
    * Implements the automatic detection whether the first identifier is a
    * module name or not.
    */
   class Reference : public Ref_base {
+    reftype_t reftype;
     /** "Processed" parameter list, after the semantic check. */
     ActualParList* parlist;
     /** "Raw" parameter list, before the semantic check. */
@@ -352,10 +353,11 @@ namespace Ttcn {
     Reference(const Reference& p);
   public:
     Reference(Identifier *p_id);
-    Reference(Identifier *p_modid, Identifier *p_id)
-      : Ref_base(p_modid, p_id), parlist(NULL), params(NULL), gen_const_prefix(false), expr_cache(NULL) { }
+    Reference(reftype_t p_reftype);
+    Reference(Identifier *p_modid, Identifier *p_id, reftype_t p_reftype = REF_BASIC)
+      : Ref_base(p_modid, p_id), reftype(p_reftype), parlist(NULL), params(NULL), gen_const_prefix(false), expr_cache(NULL) { }
     Reference(Identifier *p_modid, Identifier *p_id,
-              ParsedActualParameters *p_params);
+              ParsedActualParameters *p_params, reftype_t p_reftype = REF_BASIC);
     ~Reference();
     virtual bool has_parameters() const;
     virtual Reference *clone() const;
@@ -363,6 +365,8 @@ namespace Ttcn {
     virtual void set_my_scope(Scope* p_scope);
     virtual string get_dispname();
     virtual Common::Assignment *get_refd_assignment(bool check_parlist = true);
+    virtual reftype_t get_reftype() const { return reftype; }
+    virtual void set_reftype(reftype_t p_reftype) { reftype = p_reftype; }
     virtual const Identifier* get_modid();
     virtual const Identifier* get_id();
     virtual ActualParList *get_parlist();
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 241040471a606a0b13b1b0d12d8377d59fbedfae..47ddccab1d0ce580ee0d141d2b978035f6258aa0 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -140,14 +140,16 @@ namespace Ttcn {
       defs.add(id, p_def);
       if (parent_scope) {
 	if (parent_scope->has_ass_withId(id)) {
-	  const char *dispname = id.get_dispname().c_str();
-	  p_def->error("Definition with identifier `%s' is not unique"
-                       " in the scope hierarchy", dispname);
-	  Reference ref(0, id.clone());
-	  Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref);
-	  if (!ass) FATAL_ERROR("StatementBlock::register_def()");
-	  ass->note("Previous definition with identifier `%s' in higher "
-                     "scope unit is here", dispname);
+    if (parent_scope->get_scope_class() == NULL) {
+      const char *dispname = id.get_dispname().c_str();
+      p_def->error("Definition with identifier `%s' is not unique"
+                         " in the scope hierarchy", dispname);
+      Reference ref(0, id.clone());
+      Common::Assignment *ass = parent_scope->get_ass_bySRef(&ref);
+      if (!ass) FATAL_ERROR("StatementBlock::register_def()");
+      ass->note("Previous definition with identifier `%s' in higher "
+                       "scope unit is here", dispname);
+    }
 	} else if (parent_scope->is_valid_moduleid(id)) {
 	  p_def->warning("Definition with name `%s' hides a module identifier",
 	    id.get_dispname().c_str());
@@ -163,7 +165,9 @@ namespace Ttcn {
 
   Common::Assignment* StatementBlock::get_ass_bySRef(Ref_simple *p_ref)
   {
-    if(p_ref->get_modid()) return get_parent_scope()->get_ass_bySRef(p_ref);
+    if(p_ref->get_modid() || p_ref->get_reftype() != Ref_simple::REF_BASIC) {
+      return get_parent_scope()->get_ass_bySRef(p_ref);
+    }
     const Identifier& id=*p_ref->get_id();
     if(defs.has_key(id)) return defs[id];
     else return get_parent_scope()->get_ass_bySRef(p_ref);
@@ -3150,6 +3154,14 @@ namespace Ttcn {
     }
     if (!t_ass) goto error;
     switch (t_ass->get_asstype()) {
+    case Common::Assignment::A_VAR:
+      if (t_ass->get_Type()->get_type_refd_last()->get_typetype() != Common::Type::T_CLASS) {
+        ref_pard->error("Reference to a function or altstep was expected "
+          "instead of %s, which cannot be invoked",
+          t_ass->get_description().c_str());
+        goto error;
+      }
+      // else fall through
     case Common::Assignment::A_FUNCTION:
     case Common::Assignment::A_FUNCTION_RVAL:
     case Common::Assignment::A_FUNCTION_RTEMP:
@@ -3232,6 +3244,19 @@ error:
   {
     Error_Context cntxt(this, "In function instance");
     Common::Assignment *t_ass = ref_pard->get_refd_assignment();
+    if (t_ass->get_asstype() == Common::Assignment::A_VAR) {
+      // it could be a class object method
+      Common::Assignment* last_method = NULL;
+      t_ass->get_Type()->get_field_type(ref_pard->get_subrefs(),
+        Type::EXPECTED_DYNAMIC_VALUE, 0, false, &last_method);
+      if (last_method == NULL) {
+        ref_pard->error("Reference to a function or altstep was expected");
+      }
+      else {
+        // do the checks on the method at the end of the subreferences instead
+        t_ass = last_method;
+      }
+    }
     if (t_ass->get_PortType()) {
       ref_pard->error("Function with `port' clause cannot be called directly.");
     }
@@ -9240,6 +9265,9 @@ error:
               refd_ass->get_asstype() == Common::Assignment::A_CONST) {
             rhs_name = string("const_") + rhs_name;
           }
+          else if (ref->get_reftype() == Ref_simple::REF_THIS) {
+            rhs_name = string("this->") + rhs_name;
+          }
           if (val->can_use_increment(ref)) {
             switch (val->get_optype()) {
             case Value::OPTYPE_ADD:
@@ -9353,6 +9381,9 @@ error:
               refd_ass->get_asstype() == Common::Assignment::A_TEMPLATE) {
             rhs_name = string("template_") + rhs_name;
           }
+          else if (ref->get_reftype() == Ref_simple::REF_THIS) {
+            rhs_name = string("this->") + rhs_name;
+          }
           if (Common::Type::T_SEQOF == templ->get_my_governor()->get_typetype() ||
               Common::Type::T_ARRAY == templ->get_my_governor()->get_typetype()) {
             str = mputprintf(str, "%s.remove_all_permutations();\n", (rhs_copied ? rhs_copy : rhs_name).c_str());
@@ -11476,11 +11507,20 @@ error:
     if (!t_ass) return;
     Common::Assignment::asstype_t asstype = t_ass->get_asstype();
     switch (asstype) {
+    case Common::Assignment::A_TYPE:
+      if (t_ass->get_Type()->get_typetype() != Common::Type::T_CLASS) {
+        ref->error("Reference to a value, template, timer, port or class object "
+          "was expected instead of %s", t_ass->get_description().c_str());
+        return;
+      }
+      // else fall through
     case Common::Assignment::A_FUNCTION_RVAL:
     case Common::Assignment::A_FUNCTION_RTEMP:
     case Common::Assignment::A_EXT_FUNCTION_RVAL:
     case Common::Assignment::A_EXT_FUNCTION_RTEMP:
-    	ref->get_my_scope()->chk_runs_on_clause(t_ass, *this, "call");
+      if (asstype != Common::Assignment::A_TYPE) {
+        ref->get_my_scope()->chk_runs_on_clause(t_ass, *this, "call");
+      }
     case Common::Assignment::A_CONST:
     case Common::Assignment::A_EXT_CONST:
     case Common::Assignment::A_MODULEPAR:
@@ -11527,13 +11567,13 @@ error:
       break;
     case Common::Assignment::A_FUNCTION:
     case Common::Assignment::A_EXT_FUNCTION:
-      ref->error("Reference to a value, template, timer or port was expected "
-	"instead of a call of %s, which does not have return type",
+      ref->error("Reference to a value, template, timer, port or class object "
+	"was expected instead of a call of %s, which does not have return type",
 	t_ass->get_description().c_str());
       break;
     default:
-      ref->error("Reference to a value, template, timer or port was expected "
-	"instead of %s", t_ass->get_description().c_str());
+      ref->error("Reference to a value, template, timer, port or class object "
+	"was expected instead of %s", t_ass->get_description().c_str());
     }
   }
 
diff --git a/compiler2/ttcn3/TtcnTemplate.cc b/compiler2/ttcn3/TtcnTemplate.cc
index 15815fb0cd4211d8e630655d43cc8169ee81f830..ffd71a721505d61d167968e9357616fa1ab8f92b 100644
--- a/compiler2/ttcn3/TtcnTemplate.cc
+++ b/compiler2/ttcn3/TtcnTemplate.cc
@@ -31,6 +31,7 @@
 #include "../main.hh"
 #include "../../common/dbgnew.hh"
 #include "Attributes.hh"
+#include "Ttcnstuff.cc"
 
 namespace Ttcn {
 
@@ -2164,6 +2165,40 @@ namespace Ttcn {
     }
     case TEMPLATE_REFD: {
       Common::Assignment *ass = u.ref.ref->get_refd_assignment();
+      if (ass->get_asstype() == Common::Assignment::A_VAR) {
+        // there could be class objects in the subreferences, which would change
+        // the type of the assignment (e.g. to a var template);
+        // use the assignment after the last class object in the subreference chain
+        FieldOrArrayRefs* subrefs = u.ref.ref->get_subrefs();
+        if (subrefs != NULL) {
+          Type* type = ass->get_Type();
+          if (type->get_field_type(subrefs, Common::Type::EXPECTED_DYNAMIC_VALUE) != NULL) {
+            // subrefs are valid
+            for (size_t i = 0; i < subrefs->get_nof_refs(); ++i) {
+              type = type->get_type_refd_last();
+              FieldOrArrayRef* subref = subrefs->get_ref(i);
+              switch (subref->get_type()) {
+              case FieldOrArrayRef::FIELD_REF:
+              case FieldOrArrayRef::FUNCTION_REF:
+                if (type->get_typetype() == Common::Type::T_CLASS) {
+                  ass = type->get_class_type_body()->
+                    get_local_ass_byId(*subref->get_id());
+                  type = ass->get_Type();
+                }
+                else {
+                  type = type->get_comp_byName(*subref->get_id())->get_type();
+                }
+                break;
+              case FieldOrArrayRef::ARRAY_REF:
+                if (type->is_structured_type()) {
+                  type = type->get_ofType();
+                }
+                break;
+              }
+            }
+          }
+        }
+      }
       switch (ass->get_asstype()) {
       case Common::Assignment::A_EXT_CONST:
       case Common::Assignment::A_PAR_VAL:
@@ -2503,9 +2538,9 @@ end:
 
         if (get_template_refd_last()->templatetype == TEMPLATE_REFD)
         {
-          Assignment *formal_param_ass = get_template_refd_last()->get_reference()->get_refd_assignment();
-          if (formal_param_ass->get_asstype() >= Assignment::A_PAR_VAL)
-            if (formal_param_ass->get_asstype() <= Assignment::A_PAR_TEMPL_INOUT)
+          Common::Assignment *formal_param_ass = get_template_refd_last()->get_reference()->get_refd_assignment();
+          if (formal_param_ass->get_asstype() >= Common::Assignment::A_PAR_VAL)
+            if (formal_param_ass->get_asstype() <= Common::Assignment::A_PAR_TEMPL_INOUT)
               if (formal_param_ass->get_eval_type() != NORMAL_EVAL)
                 warning("Fuzzy parameter '%s' may change (during) the actual snapshot.",
                     get_reference()->get_dispname().c_str());
@@ -5786,43 +5821,43 @@ compile_time:
       if (derived_reference) {
         int asstype = ((Reference*)derived_reference)->get_refd_assignment()->get_asstype();
         switch (asstype) {
-          case Assignment::A_TYPE:           /**< type */
-          case Assignment::A_CONST:          /**< value (const) */
-          case Assignment::A_UNDEF:          /**< undefined/undecided (ASN.1) */
-          case Assignment::A_ERROR:          /**< erroneous; the kind cannot be deduced (ASN.1) */
-          case Assignment::A_OC:             /**< information object class (ASN.1) */
-          case Assignment::A_OBJECT:         /**< information object (ASN.1) */
-          case Assignment::A_OS:             /**< information object set (ASN.1) */
-          case Assignment::A_VS:             /**< value set (ASN.1) */
-          case Assignment::A_EXT_CONST:      /**< external constant (TTCN-3) */
-          case Assignment::A_MODULEPAR:      /**< module parameter (TTCN-3) */
-          case Assignment::A_MODULEPAR_TEMP: /**< template module parameter */
-          case Assignment::A_VAR:            /**< variable (TTCN-3) */
-          case Assignment::A_VAR_TEMPLATE:   /**< template variable: dynamic template (TTCN-3) */
-          case Assignment::A_TIMER:          /**< timer (TTCN-3) */
-          case Assignment::A_PORT:           /**< port (TTCN-3) */
-          case Assignment::A_ALTSTEP:        /**< altstep (TTCN-3) */
-          case Assignment::A_TESTCASE:       /**< testcase Assignment::(TTCN-3) */
-          case Assignment::A_PAR_TIMER:      /**< formal parameter (timer) (TTCN-3) */
-          case Assignment::A_PAR_PORT:        /**< formal parameter (port) (TTCN-3) */
-          case Assignment::A_FUNCTION:       /**< function without return type (TTCN-3) */
-          case Assignment::A_FUNCTION_RVAL:  /**< function that returns a value (TTCN-3) */
-          case Assignment::A_FUNCTION_RTEMP: /**< function that returns a template (TTCN-3) */
-          case Assignment::A_EXT_FUNCTION:   /**< external function without return type (TTCN-3) */
-          case Assignment::A_EXT_FUNCTION_RVAL:  /**< ext. func that returns a value (TTCN-3) */
-          case Assignment::A_EXT_FUNCTION_RTEMP: /**< ext. func that returns a template (TTCN-3) */
+          case Common::Assignment::A_TYPE:           /**< type */
+          case Common::Assignment::A_CONST:          /**< value (const) */
+          case Common::Assignment::A_UNDEF:          /**< undefined/undecided (ASN.1) */
+          case Common::Assignment::A_ERROR:          /**< erroneous; the kind cannot be deduced (ASN.1) */
+          case Common::Assignment::A_OC:             /**< information object class (ASN.1) */
+          case Common::Assignment::A_OBJECT:         /**< information object (ASN.1) */
+          case Common::Assignment::A_OS:             /**< information object set (ASN.1) */
+          case Common::Assignment::A_VS:             /**< value set (ASN.1) */
+          case Common::Assignment::A_EXT_CONST:      /**< external constant (TTCN-3) */
+          case Common::Assignment::A_MODULEPAR:      /**< module parameter (TTCN-3) */
+          case Common::Assignment::A_MODULEPAR_TEMP: /**< template module parameter */
+          case Common::Assignment::A_VAR:            /**< variable (TTCN-3) */
+          case Common::Assignment::A_VAR_TEMPLATE:   /**< template variable: dynamic template (TTCN-3) */
+          case Common::Assignment::A_TIMER:          /**< timer (TTCN-3) */
+          case Common::Assignment::A_PORT:           /**< port (TTCN-3) */
+          case Common::Assignment::A_ALTSTEP:        /**< altstep (TTCN-3) */
+          case Common::Assignment::A_TESTCASE:       /**< testcase Common::Assignment::(TTCN-3) */
+          case Common::Assignment::A_PAR_TIMER:      /**< formal parameter (timer) (TTCN-3) */
+          case Common::Assignment::A_PAR_PORT:        /**< formal parameter (port) (TTCN-3) */
+          case Common::Assignment::A_FUNCTION:       /**< function without return type (TTCN-3) */
+          case Common::Assignment::A_FUNCTION_RVAL:  /**< function that returns a value (TTCN-3) */
+          case Common::Assignment::A_FUNCTION_RTEMP: /**< function that returns a template (TTCN-3) */
+          case Common::Assignment::A_EXT_FUNCTION:   /**< external function without return type (TTCN-3) */
+          case Common::Assignment::A_EXT_FUNCTION_RVAL:  /**< ext. func that returns a value (TTCN-3) */
+          case Common::Assignment::A_EXT_FUNCTION_RTEMP: /**< ext. func that returns a template (TTCN-3) */
             break;
-          case Assignment::A_TEMPLATE:       /**< template (TTCN-3) */
+          case Common::Assignment::A_TEMPLATE:       /**< template (TTCN-3) */
             if(((Reference*)derived_reference)->get_parlist())
               ((Reference*)derived_reference)->get_parlist()->chk_immutability();
             break;
-          case Assignment::A_PAR_VAL:        /**< formal parameter (value) (TTCN-3) */
-          case Assignment::A_PAR_VAL_IN:     /**< formal parameter (in value) (TTCN-3) */
-          case Assignment::A_PAR_VAL_OUT:    /**< formal parameter (out value) (TTCN-3) */
-          case Assignment::A_PAR_VAL_INOUT:  /**< formal parameter (inout value) (TTCN-3) */
-          case Assignment::A_PAR_TEMPL_IN:   /**< formal parameter ([in] template) (TTCN-3) */
-          case Assignment::A_PAR_TEMPL_OUT:  /**< formal parameter (out template) (TTCN-3) */
-          case Assignment::A_PAR_TEMPL_INOUT:/**< formal parameter (inout template) (TTCN-3) */
+          case Common::Assignment::A_PAR_VAL:        /**< formal parameter (value) (TTCN-3) */
+          case Common::Assignment::A_PAR_VAL_IN:     /**< formal parameter (in value) (TTCN-3) */
+          case Common::Assignment::A_PAR_VAL_OUT:    /**< formal parameter (out value) (TTCN-3) */
+          case Common::Assignment::A_PAR_VAL_INOUT:  /**< formal parameter (inout value) (TTCN-3) */
+          case Common::Assignment::A_PAR_TEMPL_IN:   /**< formal parameter ([in] template) (TTCN-3) */
+          case Common::Assignment::A_PAR_TEMPL_OUT:  /**< formal parameter (out template) (TTCN-3) */
+          case Common::Assignment::A_PAR_TEMPL_INOUT:/**< formal parameter (inout template) (TTCN-3) */
             if (((Reference*)derived_reference)->get_refd_assignment()->get_eval_type() == FUZZY_EVAL)
               warning("Fuzzy parameter '%s' may change (during) the actual snapshot.",
                 ((Reference*)derived_reference)->get_dispname().c_str());
diff --git a/compiler2/ttcn3/Ttcnstuff.cc b/compiler2/ttcn3/Ttcnstuff.cc
index e5b222ae71851d74b6988f326ab5bdd32a78181b..d8954480e87fb8e41d4395a69a2ed5ac6849a3d3 100644
--- a/compiler2/ttcn3/Ttcnstuff.cc
+++ b/compiler2/ttcn3/Ttcnstuff.cc
@@ -2985,7 +2985,7 @@ namespace Ttcn {
                                boolean p_abstract, Common::Type* p_base_type, Reference* p_runs_on_ref,
                                Reference* p_mtc_ref, Reference* p_system_ref,
                                Definitions* p_members, StatementBlock* p_finally_block)
-  : Scope(), Location(), class_id(p_class_id), external(p_external), final(p_final), abstract(p_abstract),
+  : Scope(), Location(), class_id(p_class_id), my_def(NULL), external(p_external), final(p_final), abstract(p_abstract),
     base_type(p_base_type), runs_on_ref(p_runs_on_ref), mtc_ref(p_mtc_ref), system_ref(p_system_ref),
     members(p_members), finally_block(p_finally_block), constructor(NULL), checked(false),
     default_constructor(false)
@@ -2998,6 +2998,7 @@ namespace Ttcn {
   ClassTypeBody::ClassTypeBody(const ClassTypeBody& p)
   {
     class_id = p.class_id->clone();
+    my_def = p.my_def;
     external = p.external;
     final = p.final;
     abstract = p.abstract;
@@ -3148,8 +3149,31 @@ namespace Ttcn {
     if (p_ref == NULL || parent_scope == NULL) {
       FATAL_ERROR("ClassTypeBody::get_ass_bySRef()");
     }
+    chk();
     if (p_ref->get_modid() == NULL) {
       const Common::Identifier* id = p_ref->get_id();
+      if (p_ref->get_reftype() == Ref_simple::REF_SUPER) {
+        if (base_type == NULL) {
+          p_ref->error("Reference to `super' in class type `%s', which has "
+            "no base class", class_id->get_dispname().c_str());
+          return NULL;
+        }
+        else {
+          // send the reference to the base type, with the reftype changed to 'this'
+          p_ref->set_reftype(Ref_simple::REF_THIS);
+          Common::Assignment* ass = base_type->get_type_refd_last()->
+            get_class_type_body()->get_ass_bySRef(p_ref);
+          p_ref->set_reftype(Ref_simple::REF_SUPER);
+          return ass;
+        }
+      }
+      else if (id == NULL && p_ref->get_reftype() == Ref_simple::REF_THIS) {
+        // reference is just 'this'
+        return my_def;
+        // nothing special is needed for 'this.field' or 'this.method'
+        // (it's already been handled at the lower scopes)
+      }
+      
       if (id != NULL && has_local_ass_withId(*id)) {
         Common::Assignment* ass = get_local_ass_byId(*id);
         if (ass == NULL) {
@@ -3261,14 +3285,13 @@ namespace Ttcn {
         case Common::Assignment::A_CONST:
         case Common::Assignment::A_VAR: {
           // add a formal parameter for this member
-          Common::Identifier* id = new Common::Identifier(
-            Common::Identifier::ID_TTCN, string("p_") + member->get_id().get_ttcnname());
+          Common::Identifier* id = member->get_id().clone();
           FormalPar* fp = new FormalPar(is_template ?
             Common::Assignment::A_PAR_TEMPL_IN : Common::Assignment::A_PAR_VAL_IN,
             member->get_Type()->clone(), id, NULL);
           fp_list->add_fp(fp);
           // add a statement, that assigns the parameter's value to the member
-          Reference* ref_lhs = new Reference(NULL, member->get_id().clone());
+          Reference* ref_lhs = new Reference(NULL, id->clone(), Ref_simple::REF_THIS);
           Reference* ref_rhs = new Reference(NULL, id->clone());
           Common::Value* val_rhs = new Value(Common::Value::V_REFD, ref_rhs);
           Template* temp_rhs = new Template(val_rhs);
@@ -3389,7 +3412,50 @@ namespace Ttcn {
           "}\n"
           "}\n\n", class_id->get_name().c_str());
       }
-
+      
+      // logging function (similar to logging a record value, but with the 
+      // class name and the base class' log at the beginning)
+      target->header.class_defs = mputstr(target->header.class_defs,
+        "public:\n"
+        "virtual void log() const;\n");
+      target->source.methods = mputprintf(target->source.methods,
+        "void %s::log() const\n"
+        "{\n"
+        "TTCN_Logger::log_event_str(\"%s: { \");\n",
+        class_id->get_name().c_str(), class_id->get_dispname().c_str());
+      bool first_logged = false;
+      if (base_type != NULL) {
+        target->source.methods = mputprintf(target->source.methods,
+          "%s::log();\n",
+          base_type->get_genname_value(this).c_str());
+        first_logged = true;
+      }
+      for (size_t i = 0; i < members->get_nof_asss(); ++i) {
+        Common::Assignment* member = members->get_ass_byIndex(i);
+        switch (member->get_asstype()) {
+        case Common::Assignment::A_CONST:
+        case Common::Assignment::A_VAR:
+        case Common::Assignment::A_TEMPLATE:
+        case Common::Assignment::A_VAR_TEMPLATE:
+        case Common::Assignment::A_TIMER: // ?
+          if (first_logged) {
+            target->source.methods = mputstr(target->source.methods,
+              "TTCN_Logger::log_event_str(\", \");\n");
+          }
+          target->source.methods = mputprintf(target->source.methods,
+            "TTCN_Logger::log_event_str(\"%s := \");\n"
+            "%s.log();\n",
+            member->get_id().get_dispname().c_str(), member->get_id().get_name().c_str());
+          first_logged = true;
+          break;
+        default:
+          break; // don't log anything for methods
+        }
+      }
+      target->source.methods = mputstr(target->source.methods,
+        "TTCN_Logger::log_event_str(\" }\");\n"
+        "}\n\n");
+      
       target->header.class_defs = mputstr(target->header.class_defs, "};\n\n");
     }
     else { // external class
diff --git a/compiler2/ttcn3/Ttcnstuff.hh b/compiler2/ttcn3/Ttcnstuff.hh
index 8578acaad1318e33a4c4af0e8cc02ff46e39bfe0..7bad71098f37da2d7fa84769353b5852de872fab 100644
--- a/compiler2/ttcn3/Ttcnstuff.hh
+++ b/compiler2/ttcn3/Ttcnstuff.hh
@@ -756,6 +756,7 @@ public:
 
 class ClassTypeBody : public Common::Scope, public Common::Location {
   Common::Identifier* class_id; // not owned
+  Definition* my_def; // pointer to the class type definition (not owned)
   boolean external;
   boolean final;
   boolean abstract;
@@ -780,6 +781,8 @@ public:
   ClassTypeBody* clone() const;
   virtual ~ClassTypeBody();
   
+  void set_my_def(Definition* p_def) { my_def = p_def; }
+  
   void set_fullname(const string& p_fullname);
   void set_my_scope(Scope* p_scope);
   void dump(unsigned level) const;
@@ -788,6 +791,7 @@ public:
   virtual const ClassTypeBody* get_scope_class() const { return this; }
   Common::Identifier* get_id() const { return class_id; }
   Def_Constructor* get_constructor();
+  Common::Type* get_base_type() const { return base_type; }
   
   bool is_parent_class(const ClassTypeBody* p_class) const;
   bool has_local_ass_withId(const Identifier& p_id);
diff --git a/compiler2/ttcn3/compiler.l b/compiler2/ttcn3/compiler.l
index 7540f485d022372f0de9e441aeae648c05d126cb..f18436ce906d3d9027fff53634b24bc859712b44 100644
--- a/compiler2/ttcn3/compiler.l
+++ b/compiler2/ttcn3/compiler.l
@@ -582,6 +582,30 @@ finally {
     RETURN_LVAL(IDentifier);
   }
 }
+this {
+  if (oop_features) {
+    RETURN(ThisKeyword);
+  }
+  else {
+    Location loc(infile, yylloc);
+    loc.warning("Keyword 'this' is treated as an identifier. Activate "
+      "compiler option '-k' to use object-oriented features.");
+    yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
+    RETURN_LVAL(IDentifier);
+  }
+}
+super {
+  if (oop_features) {
+    RETURN(SuperKeyword);
+  }
+  else {
+    Location loc(infile, yylloc);
+    loc.warning("Keyword 'super' is treated as an identifier. Activate "
+      "compiler option '-k' to use object-oriented features.");
+    yylval.id = new Identifier(Identifier::ID_TTCN, string(yyleng, yytext));
+    RETURN_LVAL(IDentifier);
+  }
+}
 
   /* modifier keywords */
 
diff --git a/compiler2/ttcn3/compiler.y b/compiler2/ttcn3/compiler.y
index 97b6ad29d28f45282f94cbbc7a1ed9f4880ee8b5..e4e0c01a411d63b1d9c2f7dae7b1514cd966093f 100644
--- a/compiler2/ttcn3/compiler.y
+++ b/compiler2/ttcn3/compiler.y
@@ -781,10 +781,12 @@ static const string anyname("anytype");
 %token StartKeyword
 %token StopKeyword
 %token SubsetKeyword
+%token SuperKeyword
 %token SupersetKeyword
 %token SystemKeyword
 %token TemplateKeyword
 %token TestcaseKeyword
+%token ThisKeyword
 %token TimeoutKeyword
 %token TimestampKeyword
 %token TimerKeyword
@@ -1946,20 +1948,20 @@ optDecodedModifier
 %left '*' '/' ModKeyword RemKeyword
 %left UnarySign
 
-%expect 68
+%expect 75
 
 %start GrammarRoot
 
 /*
-XXX Source of conflicts (68 S/R):
+XXX Source of conflicts (75 S/R):
 
-1.) 10 conflicts in one state
+1.) 12 conflicts in one state
 The Expression after 'return' keyword is optional in ReturnStatement.
-For 10 tokens the parser cannot decide whether the token is a part of
+For 12 tokens the parser cannot decide whether the token is a part of
 the return expression (shift) or it is the beginning of the next statement
 (reduce).
 
-2.) 10 distinct states, each with one conflict caused by token '['
+2.) 13 distinct states, each with one conflict caused by token '['
 The local definitions in altsteps can be followed immediately by the guard
 expression. When the parser sees the '[' token it cannot decide whether it
 belongs to the local definition as array dimension or array subreference
@@ -1975,6 +1977,9 @@ The situations are the following:
 - var t v := ref.function(...)<subrefs> <here> [
 - var template t v := decmatch (...) ref <here> [
 - var t v := valueof(...)<subrefs> <here> [
+- var t v := this.field <here> [
+- var t v := this.function(...) <here> [
+- var t v := super.function(...) <here> [
 
 3.) 1 conflict
 The sequence identifier.objid can be either the beginning of a module name
@@ -1991,9 +1996,9 @@ non-standard language extension.
 
 6.) 1 Conflict due to pattern concatenation
 
-7.) 27 conflicts in one state
+7.) 29 conflicts in one state
 In the DecodedContentMatch rule a SingleExpression encased in round brackets is
-followed by an in-line template. For 27 tokens (after the ')' ) the parser cannot
+followed by an in-line template. For 29 tokens (after the ')' ) the parser cannot
 decide whether the token is the beginning of the in-line template (shift) or
 the brackets are only part of the SingleExpression itself and the conflicting
 token is the next segment in the expression (reduce).
@@ -3550,6 +3555,7 @@ ClassDef:
     type->set_location(infile, @$);
     $$ = new Def_Type($5, type);
     $$->set_location(infile, @$);
+    class_->set_my_def($$);
   }
 ;
 
@@ -8710,6 +8716,42 @@ Reference: // 490 ValueReference
     Free($2.elements);
     $$.ref->set_location(infile, @$);
   }
+| ThisKeyword '.' IDentifier optExtendedFieldReference
+  {
+    $$.is_ref = true;
+    $$.ref = new Ttcn::Reference(NULL, $3, Ref_simple::REF_THIS);
+    for (size_t i = 0; i < $4.nElements; i++) {
+      $$.ref->add($4.elements[i]);
+    }
+    Free($4.elements);
+    $$.ref->set_location(infile, @$);
+  }
+| ThisKeyword '.' IDentifier '(' optFunctionActualParList ')' optExtendedFieldReference
+  {
+    $$.is_ref = true;
+    $$.ref = new Ttcn::Reference(NULL, $3, $5, Ref_simple::REF_THIS);
+    for (size_t i = 0; i < $7.nElements; i++) {
+      $$.ref->add($7.elements[i]);
+    }
+    Free($7.elements);
+    $$.ref->set_location(infile, @$);
+  }
+| ThisKeyword
+  {
+    $$.is_ref = true;
+    $$.ref = new Ttcn::Reference(Ref_simple::REF_THIS);
+    $$.ref->set_location(infile, @$);
+  }
+| SuperKeyword '.' IDentifier '(' optFunctionActualParList ')' optExtendedFieldReference
+  {
+    $$.is_ref = true;
+    $$.ref = new Ttcn::Reference(NULL, $3, $5, Ref_simple::REF_SUPER);
+    for (size_t i = 0; i < $7.nElements; i++) {
+      $$.ref->add($7.elements[i]);
+    }
+    Free($7.elements);
+    $$.ref->set_location(infile, @$);
+  }
 ;
 
 /* A.1.6.5 Parameterization */
@@ -10620,6 +10662,18 @@ IschosenArg: /* see also Reference... */
     $$.ref->set_location(infile, @1, @4);
     $$.id = $6;
   }
+| IDentifier '.' IDentifier '(' optFunctionActualParList ')'
+  optExtendedFieldReference '.' PredefOrIdentifier
+  {
+    $$.ref = new Ttcn::Reference($1);
+    FieldOrArrayRef* funcref = new FieldOrArrayRef($3, $5);
+    funcref->set_location(infile, @3, @5);
+    $$.ref->add(funcref);
+    for (size_t i = 0; i < $7.nElements; i++) $$.ref->add($7.elements[i]);
+    Free($7.elements);
+    $$.ref->set_location(infile, @1, @7);
+    $$.id = $9;
+  }
 | IDentifier ArrayOrBitRef optExtendedFieldReference '.' PredefOrIdentifier
   {
     $$.ref = new Ttcn::Reference($1);
diff --git a/conformance_test/core_language_tests/negative_tests/15_templates.script b/conformance_test/core_language_tests/negative_tests/15_templates.script
index 7c874d025287fc8a8d59764eebb4daecb0357eb9..0c815bb18fc21711d3954c8e53790653ba391ea2 100644
--- a/conformance_test/core_language_tests/negative_tests/15_templates.script
+++ b/conformance_test/core_language_tests/negative_tests/15_templates.script
@@ -4795,7 +4795,7 @@ module NegSem_1511_ConcatenatingTemplatesOfStringAndListTypes_005 {
 <END_MODULE>
 
 <RESULT COUNT 1>
-error: at or before token `\*': syntax error, unexpected '\*', expecting Identifier or Cstring or CharKeyword
+error: at or before token `\*': syntax error, unexpected '\*'
 <END_RESULT>
 
 <END_TC>
diff --git a/conformance_test/core_language_tests/negative_tests/16-20_folders.script b/conformance_test/core_language_tests/negative_tests/16-20_folders.script
index c66c3ba686938fd6112a953ca12623890568e836..437cef07caefb6e8dd6f30a2a86aee0d2522b109 100644
--- a/conformance_test/core_language_tests/negative_tests/16-20_folders.script
+++ b/conformance_test/core_language_tests/negative_tests/16-20_folders.script
@@ -3563,7 +3563,7 @@ module NegSem_1911_log_statement_001 {
 <END_MODULE>
 
 <RESULT COUNT 1>
-error: Reference to a value, template, timer or port was expected instead of a call of function `@NegSem_1911_log_statement_001.f_no_return', which does not have return type
+error: Reference to a value, template, timer, port or class object was expected instead of a call of function `@NegSem_1911_log_statement_001.f_no_return', which does not have return type
 <END_RESULT>
 
 <END_TC>
diff --git a/core/OOP.hh b/core/OOP.hh
index 0b0a59fd08f47fb2cd318b162cf9063b83c3f20e..a3ddd55e000a1a584c074f8750a0fff5acde055c 100644
--- a/core/OOP.hh
+++ b/core/OOP.hh
@@ -14,15 +14,32 @@
 #define OOP_HH
 
 #include "Universal_charstring.hh"
+#include "Logger.hh"
 
 // OBJECT
 // ------
 
 class OBJECT {
+private:
+  size_t ref_count;
+  
+  OBJECT(const OBJECT&); // copy disabled
+  OBJECT operator=(const OBJECT&); // assignment disabled
+  boolean operator==(const OBJECT&); // equality operator disabled
 public:
-  boolean operator==(const OBJECT&) const { return TRUE; }
-  UNIVERSAL_CHARSTRING toString() const {
-    return UNIVERSAL_CHARSTRING("Object");
+  OBJECT(): ref_count(0) {}
+  virtual ~OBJECT() {
+    if (ref_count != 0) {
+      TTCN_error("Internal error: deleting an object with %lu reference(s) left.", ref_count);
+    }
+  }
+  void add_ref() { ++ref_count; }
+  boolean remove_ref() {
+    --ref_count;
+    return ref_count == 0;
+  }
+  void log() const {
+    TTCN_Logger::log_event_str("object: { }");
   }
 };
 
@@ -31,37 +48,34 @@ public:
 
 template <typename T>
 class OBJECT_REF {
-public:
-  struct object_ref_struct {
-    T* obj_ptr;
-    size_t ref_count;
-  };
-  
+  template <typename T2>
+  friend boolean operator==(null_type, const OBJECT_REF<T2>& right_val);
+  template <typename T2>
+  friend boolean operator!=(null_type, const OBJECT_REF<T2>& right_val);
 private:
-  object_ref_struct* val_ptr; // NULL if it's a null reference
+  T* ptr; // NULL if it's a null reference
   
   void clean_up() {
-    if (val_ptr != NULL) {
-      --val_ptr->ref_count;
-      if (val_ptr->ref_count == 0) {
-        delete val_ptr->obj_ptr;
-        delete val_ptr;
+    if (ptr != NULL) {
+      if (ptr->remove_ref()) {
+        delete ptr;
       }
-      val_ptr = NULL;
+      ptr = NULL;
     }
   }
   
 public:
-  OBJECT_REF(): val_ptr(NULL) {} // constructor for null reference
+  OBJECT_REF(): ptr(NULL) {} // constructor with no parameters
+
+  OBJECT_REF(null_type): ptr(NULL) {} // constructor for null reference
   
-  OBJECT_REF(T* p_obj_ptr): val_ptr(new object_ref_struct) { // constructor for new value (.create)
-    val_ptr->obj_ptr = p_obj_ptr;
-    val_ptr->ref_count = 1;
+  OBJECT_REF(T* p_ptr): ptr(p_ptr) { // constructor for new value (.create)
+    ptr->add_ref();
   }
   
-  OBJECT_REF(const OBJECT_REF<T>& p_other): val_ptr(p_other.val_ptr) { // copy constructor
-    if (val_ptr != NULL) {
-      ++val_ptr->ref_count;
+  OBJECT_REF(const OBJECT_REF<T>& p_other): ptr(p_other.ptr) { // copy constructor
+    if (ptr != NULL) {
+      ptr->add_ref();
     }
   }
   
@@ -75,45 +89,70 @@ public:
   
   OBJECT_REF& operator=(const OBJECT_REF<T>& p_other) { // assignment operator for actual reference
     clean_up();
-    if (p_other.val_ptr != NULL) {
-      val_ptr = p_other.val_ptr;
-      ++val_ptr->ref_count;
+    if (p_other.ptr != NULL) {
+      ptr = p_other.ptr;
+      ptr->add_ref();
     }
     return *this;
   }
   
-  boolean operator==(const OBJECT_REF<T>& p_other) const { // equality operator
-    if (val_ptr == p_other.val_ptr) return TRUE;
-    if (val_ptr == NULL || p_other.val_ptr == NULL) return FALSE;
-    return *val_ptr->obj_ptr == *p_other.val_ptr->obj_ptr;
+  boolean operator==(null_type) const { // equality operator (with null reference)
+    return ptr == NULL;
   }
   
-  boolean operator!=(const OBJECT_REF<T>& p_other) const { // inequality operator
-    return !(*this == p_other);
+  boolean operator!=(null_type) const { // inequality operator (with null reference)
+    return ptr != NULL;
+  }
+  
+  boolean operator==(const OBJECT_REF<T>& p_other) const { // equality operator (with actual reference)
+    return ptr == p_other.ptr;
+  }
+  
+  boolean operator!=(const OBJECT_REF<T>& p_other) const { // inequality operator (with actual reference)
+    return ptr != p_other.ptr;
   }
   
   T* operator*() { // de-referencing operator
-    if (val_ptr != NULL) {
-      return val_ptr->obj_ptr;
+    if (ptr != NULL) {
+      return ptr;
     }
     TTCN_error("Accessing a null reference.");
   }
   
   T* operator->() { // de-referencing operator (for methods)
-    if (val_ptr != NULL) {
-      return val_ptr->obj_ptr;
+    if (ptr != NULL) {
+      return ptr;
     }
     TTCN_error("Accessing a null reference.");
   }
   
   const T* operator->() const { // de-referencing operator (for constant methods)
-    if (val_ptr != NULL) {
-      return val_ptr->obj_ptr;
+    if (ptr != NULL) {
+      return ptr;
     }
     TTCN_error("Accessing a null reference.");
   }
+  
+  void log() const {
+    if (ptr == NULL) {
+      TTCN_Logger::log_event_str("null");
+    }
+    else {
+      ptr->log();
+    }
+  }
 };
 
+template<typename T>
+boolean operator==(null_type, const OBJECT_REF<T>& right_val) { // equality operator (with null reference, inverted)
+  return right_val.ptr == NULL;
+}
+
+template<typename T>
+boolean operator!=(null_type, const OBJECT_REF<T>& right_val) { // inequality operator (with null reference, inverted)
+  return right_val.ptr != NULL;
+}
+
 // EXCEPTION
 // ---------
 
diff --git a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script
index fa64dff85a34de2aa01b3d3c7d503eba7e3587a0..da7f73d712b523225bb0f4b3d6718169c3ad118f 100644
--- a/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script
+++ b/function_test/Semantic_Analyser/TTCN3_SA_ttcn3adhoc_TD.script
@@ -4380,10 +4380,10 @@ control {
 }
 <END_MODULE>
 <RESULT COUNT 2>
-(?is)\berror: at or before token `12': syntax error, unexpected Number, expecting Identifier or Cstring
+(?is)\berror: at or before token `12': syntax error, unexpected Number
 <END_RESULT>
 <RESULT COUNT 2>
-(?is)\berror: at or before token `refers': syntax error, unexpected RefersKeyword, expecting Identifier or Cstring
+(?is)\berror: at or before token `refers': syntax error, unexpected RefersKeyword
 <END_RESULT>
 <RESULT COUNT 6>
 (?is)\berror: Invalid reference expression
diff --git a/regression_test/oop/oop.ttcn b/regression_test/oop/oop.ttcn
index e1b9550f0f63ed50a1e9006e51edee492154c746..f8213cc6eb999c775024bf0da315a1ca658cd82c 100644
--- a/regression_test/oop/oop.ttcn
+++ b/regression_test/oop/oop.ttcn
@@ -28,6 +28,11 @@ type record Rec {
   IntList list
 }
 
+type union Uni {
+  integer i,
+  charstring cs
+}
+
 type class BaseClass runs on CT mtc CT system CT {
   public const integer m_const := 1;
   private const IntList m_const2 := { 1, 2, 3 };
@@ -70,6 +75,28 @@ type class BaseClass runs on CT mtc CT system CT {
   public function get_var() return charstring {
     return m_var;
   }
+  
+  public function this_test(in integer get_var, in charstring p_log_str) {
+    var integer m_const := 9;
+    if (this.m_const != 2) {
+      setverdict(fail, "this.m_const = ", this.m_const);
+    }
+    if (this.get_var() != m_var) {
+      setverdict(fail, "this.get_var() = ", this.get_var(), ", m_var = ", m_var);
+    }
+    if (log2str(this) != p_log_str) {
+      setverdict(fail, "this = ", this, ", expected: ", p_log_str);
+    }
+    var BaseClass v_ref := this;
+    if (not v_ref == this) {
+      setverdict(fail, "equality failed");
+    }
+    var BaseClass v_ref2;
+    v_ref2 := this;
+    if (this != v_ref2) {
+      setverdict(fail, "inequality failed");
+    }
+  }
 }
 finally {
   //pt.send(-1);
@@ -87,9 +114,7 @@ type class SubClass extends BaseClass {
   const octetstring m_const3 := 'AB'O; // the parser currently doesn't accept constants without initial value
   
   public function f(in integer x) return integer {
-    //return super.f(x) - 1; // not supported yet
-    m_var := m_var & int2str(x);
-    return x - 1;
+    return super.f(x) - 1;
   }
 }
 
@@ -100,9 +125,15 @@ type class @final FinalClass extends SubClass {
   private var template octetstring m_final_var_temp;
   
   public function @final f(in integer x) return integer {
-    //return super.super.f(x) + m_final_const; // not supported yet
-    m_var := m_var & int2str(x);
-    return x + m_final_const;
+    return super.f(x) + m_final_const + 1;
+  }
+  
+  public function get_uni() return Uni {
+    return { i := m_final_const };
+  }
+  
+  public function get_uni_temp() return template Uni {
+    return { cs := m_final_temp };
   }
 }
 
@@ -144,10 +175,6 @@ testcase tc_members_and_methods() runs on CT {
   var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
   var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
   
-  //log(v_base);
-  //log(v_sub);
-  //log(v_final);
-  
   log(v_base.f(6));
   log(v_sub.f(6));
   log(v_final.f(6));
@@ -163,7 +190,7 @@ testcase tc_members_and_methods() runs on CT {
   if (v_sub.f(6) != 5) {
     setverdict(fail, "v_sub.f(6) = ", v_sub.f(6));
   }
-  if (v_final.f(6) != 7) {
+  if (v_final.f(6) != 14) {
     setverdict(fail, "v_final.f(6) = ", v_final.f(6));
   }
   
@@ -186,9 +213,157 @@ testcase tc_members_and_methods() runs on CT {
   setverdict(pass);
 }
 
+testcase tc_logging() runs on CT {
+  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
+  var IntList il := { 1, 2, 4 };
+  var template float tf := (0.0 .. 10.0);
+  var BaseClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
+  var BaseClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
+
+  log(v_base);
+  log(v_sub);
+  log(v_final);
+  
+  var charstring v_base_str := "BaseClass: { m_const := 2, m_const2 := { 1, 2, 1 }, m_temp := *, m_timer := timer: { name: m_timer, default duration: none, state: inactive }, m_timer_array := { timer: { name: m_timer_array[0], default duration: none, state: inactive }, timer: { name: m_timer_array[1], default duration: none, state: inactive }, timer: { name: m_timer_array[2], default duration: none, state: inactive } }, m_var := \"a\", m_var_temp := (0.000000 .. 10.000000) }";
+  var charstring v_sub_str := "SubClass: { BaseClass: { m_const := 2, m_const2 := { 1, 2, 1 }, m_temp := *, m_timer := timer: { name: m_timer, default duration: none, state: inactive }, m_timer_array := { timer: { name: m_timer_array[0], default duration: none, state: inactive }, timer: { name: m_timer_array[1], default duration: none, state: inactive }, timer: { name: m_timer_array[2], default duration: none, state: inactive } }, m_var := \"ax\", m_var_temp := (0.000000 .. 10.000000) }, m_const3 := 'FFFF'O }";
+  var charstring v_final_str := "FinalClass: { SubClass: { BaseClass: { m_const := 2, m_const2 := { 1, 2, 1 }, m_temp := *, m_timer := timer: { name: m_timer, default duration: none, state: inactive }, m_timer_array := { timer: { name: m_timer_array[0], default duration: none, state: inactive }, timer: { name: m_timer_array[1], default duration: none, state: inactive }, timer: { name: m_timer_array[2], default duration: none, state: inactive } }, m_var := \"ax\", m_var_temp := (0.000000 .. 10.000000) }, m_const3 := 'FFFF'O }, m_final_const := 8, m_final_temp := \"x\", m_final_var := -1.500000, m_final_var_temp := * }";
+  
+  if (log2str(v_base) != v_base_str) {
+    setverdict(fail, "v_base: ", v_base);
+  }
+  if (log2str(v_sub) != v_sub_str) {
+    setverdict(fail, "v_sub: ", v_sub);
+  }
+  if (log2str(v_final) != v_final_str) {
+    setverdict(fail, "v_final: ", v_final);
+  }
+  setverdict(pass);
+}
+
+testcase tc_equality() runs on CT {
+  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
+  var BaseClass v_base2 := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
+  if (v_base == v_base2) {
+    setverdict(fail, "Equality of different objects failed");
+  }
+  if (not v_base != v_base2) {
+    setverdict(fail, "Inquality of different objects failed");
+  }
+  
+  var BaseClass v_ref := v_base;
+  if (not v_ref == v_base) {
+    setverdict(fail, "Equality of object and reference to object failed");
+  }
+  if (v_ref != v_base) {
+    setverdict(fail, "Inequality of object and reference to object failed");
+  }
+  
+  var BaseClass v_ref2 := v_ref;
+  if (not v_ref2 == v_base) {
+    setverdict(fail, "Equality of object and indirect reference to object failed");
+  }
+  if (v_ref2 != v_base) {
+    setverdict(fail, "Inequality of object and indirect reference to object failed");
+  }
+  setverdict(pass);
+}
+
+testcase tc_null() runs on CT {
+  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
+  var IntList il := { 1, 2, 4 };
+  var template float tf := (0.0 .. 10.0);
+  var SubClass v_sub := SubClass.create(4, il, "a", 'FF'O, tf);
+  var FinalClass v_final := FinalClass.create(4, il, "a", 'FF'O, tf, 8, "x", -1.5, *);
+  
+  var BaseClass v_null := null;
+  var BaseClass v_empty;
+  
+  log(v_null);
+  log(v_empty);
+  
+  if (v_base == v_null) {
+    setverdict(fail, "BaseClass equality with null reference failed");
+  }
+  if (v_base == v_empty) {
+    setverdict(fail, "BaseClass equality with empty reference failed");
+  }
+  if (v_null != v_empty) {
+    setverdict(fail, "null reference equality with empty reference failed");
+  }
+  if (v_base == null) {
+    setverdict(fail, "BaseClass equality with null value failed");
+  }
+  if (null == v_final) {
+    setverdict(fail, "FinalClass equality with null value failed");
+  }
+  if (v_null != null) {
+    setverdict(fail, "null reference equality with null value failed");
+  }
+  if (null != v_empty) {
+    setverdict(fail, "null value equality with empty reference failed");
+  }
+  setverdict(pass);
+}
+
+testcase tc_this() runs on CT {
+  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, (0.0 .. 10.0));
+  v_base.this_test(10, log2str(v_base));
+  setverdict(pass);
+}
+
+testcase tc_references() runs on CT {
+  var BaseClass v_base := BaseClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
+  var SubClass v_sub := SubClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0);
+  var FinalClass v_final := FinalClass.create(4, { 1, 2, 4 }, "a", 'FF'O, 1.0, 8, "x", -1.5, *);
+  
+  var BaseClass v_ref1;
+  if (v_ref1 != null) {
+    setverdict(fail, "#1");
+  }
+  v_ref1 := v_base;
+  if (v_ref1 != v_base) {
+    setverdict(fail, "#2");
+  }
+  var integer v_int := v_final.f(1);
+  if (v_int != 9) {
+    setverdict(fail, "#3, ", v_final.f(1));
+  }
+  v_int := v_final.f(2);
+  if (v_int != 10) {
+    setverdict(fail, "#4, ", v_final.f(2));
+  }
+  if (not isbound(v_final.f2(3).list[1])) {
+    setverdict(fail, "#5");
+  }
+  if (not isvalue(v_base.m_var_temp)) {
+    setverdict(fail, "#6");
+  }
+  if (not ispresent(v_base.m_var_temp)) {
+    setverdict(fail, "#7");
+  }
+  if (ischosen(v_final.get_uni().cs)) {
+    setverdict(fail, "#8");
+  }
+  if (not ischosen(v_final.get_uni_temp().cs)) {
+    setverdict(fail, "#9");
+  }
+  if (v_final.f2(3).list[1] + v_final.f(-6) != v_base.f(3) * float2int(valueof(v_sub.m_var_temp))) {
+    setverdict(fail, "#10, ", v_final.f2(3).list[1] + v_final.f(-6), " != ", v_base.f(3) * float2int(valueof(v_sub.m_var_temp)));
+  }
+  if (match(v_final.get_uni(), v_final.get_uni_temp())) {
+    setverdict(fail, "#11, ", match(v_final.get_uni(), v_final.get_uni_temp()));
+  }
+  setverdict(pass);
+}
+
 
 control {
   execute(tc_members_and_methods());
+  execute(tc_logging());
+  execute(tc_equality());
+  execute(tc_null());
+  execute(tc_this());
+  execute(tc_references());
 }
 
 }