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.
let
var me := 0
in
me
end
$ 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.
let
var me := 0
function id(me : int) : int = me
in
print_int(me)
end
$ 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,
me
$ tc -bBA nome.tig
nome.tig:1.1-2: undeclared variable: me
$ echo $?
4
or redefined names.
let
type me = {}
type me = {}
function twice(a: int, a: int) : int = a + a
in
me {} = me {}
end
$ 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.
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
/* == 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
$ 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.
let
type box = { value : int }
type dup = { value : int, value : string }
var box := box { value = 51 }
in
box.head
end
$ 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
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.
let
type rec = { a : unknown }
in
rec { a = 42 }
end
$ 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.
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
/* == 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
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).
let
/* Super class doesn't exist. */
class Z extends Ghost {}
in
end
$ 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.
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
/* == 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