TC-3 Samples

Binding is relating a name use to its definition.

Warning

You must strictly follow the format specified below when displaying binding addresses. Addresses must be displayed right after declarations or usages identifiers:

identifier /* 0x55bbe7bdc230 */

Display addresses only when needed. Look closely at the samples.

me.tig
let
  var me := 0
in
  me
end
tc -XbBA me.tig
$ tc -XbBA me.tig
/* == Abstract Syntax Tree. == */

function _main /* 0x5608586a1450 */() =
  (
    let
      var me /* 0x5608586a1770 */ := 0
    in
      me /* 0x5608586a1770 */
    end;
    ()
  )
$ echo $?
0

This is harder when there are several occurrences of the same name. Note that primitive types are accepted, but have no pre-declaration, contrary to primitive functions.

meme.tig
let
  var me := 0
  function id(me : int) : int = me
in
  print_int(me)
end
tc -bBA meme.tig
$ tc -bBA meme.tig
/* == Abstract Syntax Tree. == */

primitive print /* 0x55b96f0c6a60 */(string /* 0x55b96f0c41a0 */ : string /* 0 */)
primitive print_err /* 0x55b96f0c5980 */(string /* 0x55b96f0c67f0 */ : string /* 0 */)
primitive print_int /* 0x55b96f0c6770 */(int /* 0x55b96f0c66f0 */ : int /* 0 */)
primitive flush /* 0x55b96f0c6e00 */()
primitive getchar /* 0x55b96f0f89e0 */() : string /* 0 */
primitive ord /* 0x55b96f0d8550 */(string /* 0x55b96f0d4d60 */ : string /* 0 */) : int /* 0 */
primitive chr /* 0x55b96f0d7a30 */(code /* 0x55b96f0f8bd0 */ : int /* 0 */) : string /* 0 */
primitive size /* 0x55b96f0c8560 */(string /* 0x55b96f0c8430 */ : string /* 0 */) : int /* 0 */
primitive streq /* 0x55b96f0da810 */(s1 /* 0x55b96f0da560 */ : string /* 0 */, s2 /* 0x55b96f0da720 */ : string /* 0 */) : int /* 0 */
primitive strcmp /* 0x55b96f0dabb0 */(s1 /* 0x55b96f0da950 */ : string /* 0 */, s2 /* 0x55b96f0daac0 */ : string /* 0 */) : int /* 0 */
primitive substring /* 0x55b96f0d8a00 */(string /* 0x55b96f0dacf0 */ : string /* 0 */, start /* 0x55b96f0daeb0 */ : int /* 0 */, length /* 0x55b96f0d8910 */ : int /* 0 */) : string /* 0 */
primitive concat /* 0x55b96f0d8e00 */(fst /* 0x55b96f0d8b90 */ : string /* 0 */, snd /* 0x55b96f0d8d10 */ : string /* 0 */) : string /* 0 */
primitive not /* 0x55b96f0d91a0 */(boolean /* 0x55b96f0d9030 */ : int /* 0 */) : int /* 0 */
primitive exit /* 0x55b96f0d93b0 */(status /* 0x55b96f0d9330 */ : int /* 0 */)
function _main /* 0x55b96f0d9640 */() =
  (
    let
      var me /* 0x55b96f0c4770 */ := 0
      function id /* 0x55b96f0c4310 */(me /* 0x55b96f0c4450 */ : int /* 0 */) : int /* 0 */ =
        me /* 0x55b96f0c4450 */
    in
      print_int /* 0x55b96f0c6770 */(me /* 0x55b96f0c4770 */)
    end;
    ()
  )
$ echo $?
0

TC-3 is in charge of incorrect uses of the names, such as undefined names,

nome.tig
me
tc -bBA nome.tig
$ tc -bBA nome.tig
nome.tig:1.1-2: undeclared variable: me
$ echo $?
4

or redefined names.

tome.tig
let
  type me = {}
  type me = {}
  function twice(a: int, a: int) : int = a + a
in
  me {} = me {}
end
tc -bBA tome.tig
$ tc -bBA tome.tig
tome.tig:3.3-14: redefinition: me
tome.tig:2.3-14: first definition
tome.tig:4.25-31: redefinition: a
tome.tig:4.18-23: first definition
$ echo $?
4

In addition to binding names, --bindings-compute is also in charge of binding the break to their corresponding loop construct.

breaks-in-embedded-loops.tig
let var x := 0 in
  while 1 do
  (
    for i := 0 to 10 do
    (
      x := x + i;
      if x >= 42 then
        break
    );
    if x >= 51 then
      break
  )
end
tc -XbBA breaks-in-embedded-loops.tig
$ tc -XbBA breaks-in-embedded-loops.tig
/* == Abstract Syntax Tree. == */

function _main /* 0x563b3c9511a0 */() =
  (
    let
      var x /* 0x563b3c953a60 */ := 0
    in
      while /* 0x563b3c952060 */ 1 do
        (
          for /* 0x563b3c9554c0 */ i /* 0x563b3c951310 */ := 0 to 10 do
            (
              x /* 0x563b3c953a60 */ := x /* 0x563b3c953a60 */ + i /* 0x563b3c951310 */;
              if x /* 0x563b3c953a60 */ >= 42
                then break /* 0x563b3c9554c0 */
                else ()
            );
          if x /* 0x563b3c953a60 */ >= 51
            then break /* 0x563b3c952060 */
            else ()
        )
    end;
    ()
  )
$ echo $?
0
break.tig
break
tc -b break.tig
$ tc -b break.tig
break.tig:1.1-5: `break' outside any loop
$ echo $?
4

Embedded loops show that there is scoping for breaks. Beware that there are places, apparently inside loops, where breaks make no sense.

Although it is a matter of definitions and uses of names, record members are not bound here, because it is easier to implement during type checking. Likewise, duplicate fields are to be reported during type checking.

box.tig
let
  type     box = { value : int }
  type     dup = { value : int, value : string }
  var      box := box { value = 51 }
in
  box.head
end
tc -XbBA box.tig
$ tc -XbBA box.tig
/* == Abstract Syntax Tree. == */

function _main /* 0x5614c54ca450 */() =
  (
    let
      type box /* 0x5614c54ccf70 */ = { value : int /* 0 */ }
      type dup /* 0x5614c54cc110 */ = {
        value : int /* 0 */,
        value : string /* 0 */
      }
      var box /* 0x5614c54ca770 */ := box /* 0x5614c54ccf70 */ { value = 51 }
    in
      box /* 0x5614c54ca770 */.head
    end;
    ()
  )
$ echo $?
0
tc -T box.tig
$ tc -T box.tig
box.tig:3.33-46: identifier multiply defined: value
box.tig:6.3-10: invalid field: head
$ echo $?
5

But apart from these field-specific checks delayed at TC-4, TC-3 should report other name-related errors. In particular, a field with an invalid type name is a binding error (related to the field’s type, not the field itself) to be reported at TC-3.

unknown-field-type.tig
let
  type rec = { a : unknown }
in
  rec { a = 42 }
end
tc -XbBA unknown-field-type.tig
$ tc -XbBA unknown-field-type.tig
unknown-field-type.tig:2.20-26: undeclared type: unknown
$ echo $?
4

Likewise, class members (both attributes and methods) are not to be bound at TC-3, but at the type-checking stage (see TC-4, Type Checking). Therefore, no bindings are to be displayed in regards to object at TC-3.

bad-member-bindings.tig
let
  type C = class {}
  var c := new C
in
  c.missing_method();
  c.missing_attribute
end
tc -X --object-bindings-compute -BA bad-member-bindings.tig
$ tc -X --object-bindings-compute -BA bad-member-bindings.tig
/* == Abstract Syntax Tree. == */

function _main /* 0x558290a36450 */() =
  (
    let
      type C /* 0x558290a39100 */ = 
      class extends Object /* 0 */
      {
      }
      var c /* 0x558290a36770 */ := new C /* 0x558290a39100 */
    in
      (
        c /* 0x558290a36770 */.missing_method();
        c /* 0x558290a36770 */.missing_attribute
      )
    end;
    ()
  )
$ echo $?
0
tc --object-types-compute bad-member-bindings.tig
$ tc --object-types-compute bad-member-bindings.tig
bad-member-bindings.tig:5.3-20: unknown method: missing_method
bad-member-bindings.tig:6.3-21: unknown attribute: missing_attribute
$ echo $?
5

Concerning the super class type, the compiler should just check that this type exists in the environment at TC-3, Bindings. Other checks are left to TC-4 (see TC-4 Samples).

missing-super-class.tig
let
  /* Super class doesn't exist.  */
  class Z extends Ghost {}
in
end
tc -X --object-bindings-compute -BA missing-super-class.tig
$ tc -X --object-bindings-compute -BA missing-super-class.tig
missing-super-class.tig:3.19-23: undeclared type: Ghost
$ echo $?
4

The self identifier is not a reserved keyword, it can be used to name variables, functions and types, even inside a class. When used inside a method, self refers to the current instance of the object if no variable named self is present in the current scope.

self.tig
let
  class self
  {
    var self : self := nil
    method self() : self = self.self
  }

  var self : self := new self

  class foo
  {
    var self := self
    method self(self : self) : self = self.self
  }
in
end
tc -X --object-bindings-compute -BA self.tig
$ tc -X --object-bindings-compute -BA self.tig
/* == Abstract Syntax Tree. == */

function _main /* 0x55c298f8d980 */() =
  (
    let
      type self /* 0x55c298f8ecf0 */ = 
      class extends Object /* 0 */
      {
        var self : self /* 0x55c298f8ecf0 */ := nil
        method self() : self /* 0x55c298f8ecf0 */ =
          self /* 0 */.self
      }
      var self /* 0x55c298f8c310 */ : self /* 0x55c298f8ecf0 */ := new self /* 0x55c298f8ecf0 */
      type foo /* 0x55c298f8c290 */ = 
      class extends Object /* 0 */
      {
        var self := self /* 0x55c298f8c310 */
        method self(self /* 0x55c298f8ea60 */ : self /* 0x55c298f8ecf0 */) : self /* 0x55c298f8ecf0 */ =
          self /* 0x55c298f8ea60 */.self
      }
    in
      ()
    end;
    ()
  )
$ echo $?
0