Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/Makefile	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -51,5 +51,8 @@
 	src/stree.c \
 	src/strtab.c \
-	src/symbol.c
+	src/stype.c \
+	src/stype_expr.c \
+	src/symbol.c \
+	src/tdata.c
 
 include ../Makefile.common
Index: uspace/app/sbi/src/ancr.c
===================================================================
--- uspace/app/sbi/src/ancr.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/ancr.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -174,5 +174,5 @@
 	do {
 		node_sym = csi_to_symbol(node);
-		symbol_print_fqn(prog, node_sym);
+		symbol_print_fqn(node_sym);
 		printf(", ");
 
@@ -196,4 +196,4 @@
 
 	node_sym = csi_to_symbol(node);
-	symbol_print_fqn(prog, node_sym);
+	symbol_print_fqn(node_sym);
 }
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/builtin.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -44,5 +44,8 @@
 static stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name);
 static void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name);
-static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name);
+static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name,
+    stree_texpr_t *type);
+
+static stree_texpr_t *builtin_mktype_string_array(void);
 
 static void builtin_write_line(run_t *run);
@@ -86,15 +89,20 @@
 
 	bi_exec = builtin_declare_fun(csi, "Exec");
-	builtin_fun_add_vararg(bi_exec, "args");
-}
-
-void builtin_run_proc(run_t *run, stree_symbol_t *proc_sym)
-{
+	builtin_fun_add_vararg(bi_exec, "args",
+	    builtin_mktype_string_array());
+}
+
+void builtin_run_proc(run_t *run, stree_proc_t *proc)
+{
+	stree_symbol_t *fun_sym;
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Run builtin procedure.\n");
 #endif
-	if (proc_sym == bi_write_line) {
+	fun_sym = proc->outer_symbol;
+
+	if (fun_sym == bi_write_line) {
 		builtin_write_line(run);
-	} else if (proc_sym == bi_exec) {
+	} else if (fun_sym == bi_exec) {
 		builtin_exec(run);
 	} else {
@@ -109,5 +117,5 @@
 	stree_fun_t *fun;
 	stree_csimbr_t *csimbr;
-	stree_symbol_t *symbol;
+	stree_symbol_t *fun_sym;
 
 	ident = stree_ident_new();
@@ -116,5 +124,6 @@
 	fun = stree_fun_new();
 	fun->name = ident;
-	fun->body = NULL;
+	fun->proc = stree_proc_new();
+	fun->proc->body = NULL;
 	list_init(&fun->args);
 
@@ -122,12 +131,13 @@
 	csimbr->u.fun = fun;
 
-	symbol = stree_symbol_new(sc_fun);
-	symbol->u.fun = fun;
-	symbol->outer_csi = csi;
-	fun->symbol = symbol;
+	fun_sym = stree_symbol_new(sc_fun);
+	fun_sym->u.fun = fun;
+	fun_sym->outer_csi = csi;
+	fun->symbol = fun_sym;
+	fun->proc->outer_symbol = fun_sym;
 
 	list_append(&csi->members, csimbr);
 
-	return symbol;
+	return fun_sym;
 }
 
@@ -150,5 +160,6 @@
 
 /** Add variadic formal parameter to function. */
-static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name)
+static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name,
+    stree_texpr_t *type)
 {
 	stree_proc_arg_t *proc_arg;
@@ -161,7 +172,32 @@
 	proc_arg->name = stree_ident_new();
 	proc_arg->name->sid = strtab_get_sid(name);
-	proc_arg->type = NULL; /* XXX */
+	proc_arg->type = type;
 
 	fun->varg = proc_arg;
+}
+
+/** Construct a @c string[] type expression. */
+static stree_texpr_t *builtin_mktype_string_array(void)
+{
+	stree_texpr_t *tstring;
+	stree_texpr_t *tsarray;
+	stree_tliteral_t *tliteral;
+	stree_tindex_t *tindex;
+
+	/* Construct @c string */
+	tstring = stree_texpr_new(tc_tliteral);
+	tliteral = stree_tliteral_new(tlc_string);
+	tstring->u.tliteral = tliteral;
+
+	/* Construct the indexing node */
+	tsarray = stree_texpr_new(tc_tindex);
+	tindex = stree_tindex_new();
+	tsarray->u.tindex = tindex;
+
+	tindex->base_type = tstring;
+	tindex->n_args = 1;
+	list_init(&tindex->args);
+
+	return tsarray;
 }
 
Index: uspace/app/sbi/src/builtin.h
===================================================================
--- uspace/app/sbi/src/builtin.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/builtin.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -33,5 +33,5 @@
 
 void builtin_declare(stree_program_t *program);
-void builtin_run_proc(run_t *run, stree_symbol_t *proc_sym);
+void builtin_run_proc(run_t *run, stree_proc_t *proc);
 
 #endif
Index: uspace/app/sbi/src/debug.h
===================================================================
--- uspace/app/sbi/src/debug.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/debug.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -33,4 +33,7 @@
 //#define DEBUG_PARSE_TRACE
 
+/** Uncomment this to get verbose debugging messagges during typing. */
+//#define DEBUG_TYPE_TRACE
+
 /** Uncomment this to get verbose debugging messages during execution. */
 //#define DEBUG_RUN_TRACE
Index: uspace/app/sbi/src/list.c
===================================================================
--- uspace/app/sbi/src/list.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/list.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -130,4 +130,10 @@
 }
 
+/** Change node data. */
+void list_node_setdata(list_node_t *node, void *data)
+{
+	node->data = data;
+}
+
 /** Create new node. */
 static list_node_t *list_node_new(void *data)
Index: uspace/app/sbi/src/list.h
===================================================================
--- uspace/app/sbi/src/list.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/list.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -44,4 +44,6 @@
 bool_t list_is_empty(list_t *list);
 
+void list_node_setdata(list_node_t *node, void *data);
+
 #define list_node_data(node, dtype) ((dtype)(node->data))
 
Index: uspace/app/sbi/src/main.c
===================================================================
--- uspace/app/sbi/src/main.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/main.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -36,4 +36,5 @@
 #include "strtab.h"
 #include "stree.h"
+#include "stype.h"
 #include "input.h"
 #include "lex.h"
@@ -49,4 +50,5 @@
 	parse_t parse;
 	stree_program_t *program;
+	stype_t stype;
 	run_t run;
 	int rc;
@@ -78,4 +80,8 @@
 	ancr_module_process(program, parse.cur_mod);
 
+	/* Type program. */
+	stype.program = program;
+	stype_module(&stype, program->module);
+
 	/* Run program. */
 	run_init(&run);
Index: uspace/app/sbi/src/mytypes.h
===================================================================
--- uspace/app/sbi/src/mytypes.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/mytypes.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -56,4 +56,6 @@
 #include "stree_t.h"
 #include "strtab_t.h"
+#include "stype_t.h"
+#include "tdata_t.h"
 
 #endif
Index: uspace/app/sbi/src/p_type.c
===================================================================
--- uspace/app/sbi/src/p_type.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/p_type.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -194,13 +194,12 @@
 {
 	stree_tliteral_t *tliteral;
-
-	tliteral = stree_tliteral_new();
+	tliteral_class_t tlc;
 
 	switch (lcur_lc(parse)) {
 	case lc_int:
-		tliteral->tlc = tlc_int;
+		tlc = tlc_int;
 		break;
 	case lc_string:
-		tliteral->tlc = tlc_string;
+		tlc = tlc_string;
 		break;
 	default:
@@ -210,4 +209,5 @@
 	lskip(parse);
 
+	tliteral = stree_tliteral_new(tlc);
 	return tliteral;
 }
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/parse.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -35,4 +35,5 @@
 #include <assert.h>
 #include <stdlib.h>
+#include "debug.h"
 #include "lex.h"
 #include "list.h"
@@ -133,8 +134,9 @@
 	csi = stree_csi_new(cc);
 	csi->name = parse_ident(parse);
-/*
+
+#ifdef DEBUG_PARSE_TRACE
 	printf("parse_csi: csi=%p, csi->name = %p (%s)\n", csi, csi->name,
 	    strtab_get_str(csi->name->sid));
-*/
+#endif
 	if (lcur_lc(parse) == lc_colon) {
 		/* Inheritance list */
@@ -193,4 +195,5 @@
 		symbol->outer_csi = outer_csi;
 		fun->symbol = symbol;
+		fun->proc->outer_symbol = symbol;
 		break;
 	case lc_var:
@@ -213,4 +216,8 @@
 		symbol->outer_csi = outer_csi;
 		prop->symbol = symbol;
+		if (prop->getter)
+			prop->getter->outer_symbol = symbol;
+		if (prop->setter)
+			prop->setter->outer_symbol = symbol;
 		break;
 	default:
@@ -235,4 +242,8 @@
 	lmatch(parse, lc_lparen);
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing function '%s'.\n", strtab_get_str(fun->name->sid));
+#endif
+
 	list_init(&fun->args);
 
@@ -242,4 +253,5 @@
 		while (b_true) {
 			arg = parse_proc_arg(parse);
+
 			if (stree_arg_has_attr(arg, aac_packed)) {
 				fun->varg = arg;
@@ -266,5 +278,6 @@
 
 	lmatch(parse, lc_is);
-	fun->body = parse_block(parse);
+	fun->proc = stree_proc_new();
+	fun->proc->body = parse_block(parse);
 	lmatch(parse, lc_end);
 
@@ -342,20 +355,30 @@
 			lskip(parse);
 			lmatch(parse, lc_is);
-			if (prop->getter_body != NULL) {
+			if (prop->getter != NULL) {
 				printf("Error: Duplicate getter.\n");
 				exit(1);
 			}
-			prop->getter_body = parse_block(parse);
+
+			/* Create setter procedure */
+			prop->getter = stree_proc_new();
+			prop->getter->body = parse_block(parse);
+
 			lmatch(parse, lc_end);
 			break;
 		case lc_set:
 			lskip(parse);
-			prop->setter_arg_name = parse_ident(parse);
+			prop->setter_arg = stree_proc_arg_new();
+			prop->setter_arg->name = parse_ident(parse);
+			prop->setter_arg->type = prop->type;
 			lmatch(parse, lc_is);
-			if (prop->setter_body != NULL) {
+			if (prop->setter != NULL) {
 				printf("Error: Duplicate setter.\n");
 				exit(1);
 			}
-			prop->setter_body = parse_block(parse);
+
+			/* Create setter procedure */
+			prop->setter = stree_proc_new();
+			prop->setter->body = parse_block(parse);
+
 			lmatch(parse, lc_end);
 			break;
@@ -390,4 +413,7 @@
 	}
 
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsed arg attr, type=%p.\n", arg->type);
+#endif
 	return arg;
 }
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/rdata.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -243,57 +243,4 @@
 }
 
-rdata_titem_t *rdata_titem_new(titem_class_t tic)
-{
-	rdata_titem_t *titem;
-
-	titem = calloc(1, sizeof(rdata_titem_t));
-	if (titem == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	titem->tic = tic;
-	return titem;
-}
-
-rdata_tarray_t *rdata_tarray_new(void)
-{
-	rdata_tarray_t *tarray;
-
-	tarray = calloc(1, sizeof(rdata_tarray_t));
-	if (tarray == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	return tarray;
-}
-
-rdata_tcsi_t *rdata_tcsi_new(void)
-{
-	rdata_tcsi_t *tcsi;
-
-	tcsi = calloc(1, sizeof(rdata_tcsi_t));
-	if (tcsi == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	return tcsi;
-}
-
-rdata_tprimitive_t *rdata_tprimitive_new(void)
-{
-	rdata_tprimitive_t *tprimitive;
-
-	tprimitive = calloc(1, sizeof(rdata_tprimitive_t));
-	if (tprimitive == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	return tprimitive;
-}
-
 void rdata_array_alloc_element(rdata_array_t *array)
 {
@@ -447,54 +394,4 @@
 }
 
-/** Get item var-class.
- *
- * Get var-class of @a item, regardless whether it is a value or address.
- * (I.e. the var class of the value or variable at the given address).
- */
-var_class_t rdata_item_get_vc(rdata_item_t *item)
-{
-	var_class_t vc;
-
-	switch (item->ic) {
-	case ic_value:
-		vc = item->u.value->var->vc;
-		break;
-	case ic_address:
-		switch (item->u.address->ac) {
-		case ac_var:
-			vc = item->u.address->u.var_a->vref->vc;
-			break;
-		case ac_prop:
-			printf("Unimplemented: Get property address "
-			    "varclass.\n");
-			exit(1);
-		default:
-			assert(b_false);
-		}
-		break;
-	default:
-		assert(b_false);
-	}
-
-	return vc;
-}
-
-/** Determine if CSI @a a is derived from CSI described by type item @a tb. */
-bool_t rdata_is_csi_derived_from_ti(stree_csi_t *a, rdata_titem_t *tb)
-{
-	bool_t res;
-
-	switch (tb->tic) {
-	case tic_tcsi:
-		res = stree_is_csi_derived_from_csi(a, tb->u.tcsi->csi);
-		break;
-	default:
-		printf("Error: Base type is not a CSI.\n");
-		exit(1);
-	}
-
-	return res;
-}
-
 void rdata_item_print(rdata_item_t *item)
 {
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/rdata.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -48,9 +48,4 @@
 rdata_string_t *rdata_string_new(void);
 
-rdata_titem_t *rdata_titem_new(titem_class_t tic);
-rdata_tarray_t *rdata_tarray_new(void);
-rdata_tcsi_t *rdata_tcsi_new(void);
-rdata_tprimitive_t *rdata_tprimitive_new(void);
-
 void rdata_array_alloc_element(rdata_array_t *array);
 void rdata_var_copy(rdata_var_t *src, rdata_var_t **dest);
@@ -59,7 +54,4 @@
 void rdata_var_write(rdata_var_t *var, rdata_value_t *value);
 
-var_class_t rdata_item_get_vc(rdata_item_t *item);
-bool_t rdata_is_csi_derived_from_ti(stree_csi_t *a, rdata_titem_t *tb);
-
 void rdata_item_print(rdata_item_t *item);
 
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/rdata_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -171,8 +171,11 @@
 /** Property address.
  *
- * When accessing part of a property that is non-scalar and mutable,
- * a read-modify-write (or get-modify-set) operation is necessary.
- * To accomodate this, the address item must hold a temporary copy of the
- * property value.
+ * When an access or index operation is performed on a property, the getter
+ * is run and the prefetched value is stored in @c tvalue. If the property
+ * is a non-scalar value type (a struct), then we might want to point to
+ * the proper @c var node inside it. @c tpos is used for this purpose.
+ *
+ * The assignment operator will modify @c tvalue and at the end the setter
+ * is called to store @c tvalue back into the property.
  */
 typedef struct {
@@ -236,47 +239,3 @@
 } rdata_item_t;
 
-/** Primitive type. */
-typedef struct {
-} rdata_tprimitive_t;
-
-/** Class, struct or interface type. */
-typedef struct {
-	struct stree_csi *csi;
-} rdata_tcsi_t;
-
-/** Array type. */
-typedef struct {
-	/** Base type item */
-	struct rdata_titem *base_ti;
-
-	/** Rank */
-	int rank;
-
-	/** Extents */
-	list_t extents; /* of stree_expr_t */
-} rdata_tarray_t;
-
-/** Generic type. */
-typedef struct {
-} rdata_tgeneric_t;
-
-typedef enum {
-	tic_tprimitive,
-	tic_tcsi,
-	tic_tarray,
-	tic_tgeneric
-} titem_class_t;
-
-/** Type item, the result of evaluating a type expression. */
-typedef struct rdata_titem {
-	titem_class_t tic;
-
-	union {
-		rdata_tprimitive_t *tprimitive;
-		rdata_tcsi_t *tcsi;
-		rdata_tarray_t *tarray;
-		rdata_tgeneric_t *tgeneric;
-	} u;
-} rdata_titem_t;
-
 #endif
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -43,4 +43,5 @@
 #include "strtab.h"
 #include "symbol.h"
+#include "tdata.h"
 
 #include "run.h"
@@ -57,4 +58,5 @@
 
 static bool_t run_exc_match(run_t *run, stree_except_t *except_c);
+static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *aprop);
 
 static void run_aprop_read(run_t *run, rdata_addr_prop_t *addr_prop,
@@ -102,5 +104,5 @@
 
 #ifdef DEBUG_RUN_TRACE
-	printf("Found function '"); symbol_print_fqn(prog, main_fun_sym);
+	printf("Found function '"); symbol_print_fqn(main_fun_sym);
 	printf("'.\n");
 #endif
@@ -108,5 +110,5 @@
 	/* Run function @c main. */
 	list_init(&main_args);
-	run_proc_ar_create(run, NULL, main_fun_sym, main_fun->body, &proc_ar);
+	run_proc_ar_create(run, NULL, main_fun->proc, &proc_ar);
 	run_proc_ar_set_args(run, proc_ar, &main_args);
 	run_proc(run, proc_ar, &res);
@@ -123,12 +125,12 @@
 void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res)
 {
-	stree_symbol_t *proc_sym;
+	stree_proc_t *proc;
 	list_node_t *node;
 
-	proc_sym = proc_ar->proc_sym;
+	proc = proc_ar->proc;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Start executing function '");
-	symbol_print_fqn(run->program, proc_sym);
+	symbol_print_fqn(proc_sym);
 	printf("'.\n");
 #endif
@@ -137,8 +139,8 @@
 
 	/* Run main procedure block. */
-	if (proc_ar->proc_block != NULL) {
-		run_block(run, proc_ar->proc_block);
+	if (proc->body != NULL) {
+		run_block(run, proc->body);
 	} else {
-		builtin_run_proc(run, proc_sym);
+		builtin_run_proc(run, proc);
 	}
 
@@ -157,5 +159,5 @@
 #ifdef DEBUG_RUN_TRACE
 	printf("Done executing procedure '");
-	symbol_print_fqn(run->program, proc_sym);
+	symbol_print_fqn(proc);
 	printf("'.\n");
 
@@ -469,5 +471,5 @@
 	rdata_var_t *payload_v;
 	rdata_object_t *payload_o;
-	rdata_titem_t *etype;
+	tdata_item_t *etype;
 
 	payload = run->thread_ar->exc_payload;
@@ -491,5 +493,5 @@
 #ifdef DEBUG_RUN_TRACE
 	printf("Active exception: '");
-	symbol_print_fqn(run->program, payload_o->class_sym);
+	symbol_print_fqn(payload_o->class_sym);
 	printf("'.\n");
 #endif
@@ -498,7 +500,8 @@
 
 	/* Evaluate type expression in except clause. */
-	run_texpr(run, except_c->etype, &etype);
-
-	return rdata_is_csi_derived_from_ti(payload_o->class_sym->u.csi,
+	run_texpr(run->program, run_get_current_csi(run), except_c->etype,
+	    &etype);
+
+	return tdata_is_csi_derived_from_ti(payload_o->class_sym->u.csi,
 	    etype);
 }
@@ -556,5 +559,5 @@
 
 	proc_ar = run_get_current_proc_ar(run);
-	return proc_ar->proc_sym->outer_csi;
+	return proc_ar->proc->outer_symbol->outer_csi;
 }
 
@@ -606,6 +609,6 @@
 
 /** Construct a function AR. */
-void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_symbol_t *proc_sym,
-    stree_block_t *proc_block, run_proc_ar_t **rproc_ar)
+void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
+    run_proc_ar_t **rproc_ar)
 {
 	run_proc_ar_t *proc_ar;
@@ -617,6 +620,5 @@
 	proc_ar = run_proc_ar_new();
 	proc_ar->obj = obj;
-	proc_ar->proc_sym = proc_sym;
-	proc_ar->proc_block = proc_block;
+	proc_ar->proc = proc;
 	list_init(&proc_ar->block_ar);
 
@@ -642,4 +644,5 @@
 	list_t *args;
 	stree_proc_arg_t *varg;
+	stree_symbol_t *outer_symbol;
 
 	run_block_ar_t *block_ar;
@@ -655,19 +658,22 @@
 	int n_vargs, idx;
 
+	(void) run;
+
 	/* AR should have been created with run_proc_ar_create(). */
-	assert(proc_ar->proc_sym != NULL);
+	assert(proc_ar->proc != NULL);
+	outer_symbol = proc_ar->proc->outer_symbol;
 
 	/*
-	 * The procedure being activated should be a member function or
+	 * The procedure being activated should belong to a member function or
 	 * property getter/setter.
 	 */
-	switch (proc_ar->proc_sym->sc) {
+	switch (outer_symbol->sc) {
 	case sc_fun:
-		fun = symbol_to_fun(proc_ar->proc_sym);
+		fun = symbol_to_fun(outer_symbol);
 		args = &fun->args;
 		varg = fun->varg;
 		break;
 	case sc_prop:
-		prop = symbol_to_prop(proc_ar->proc_sym);
+		prop = symbol_to_prop(outer_symbol);
 		args = &prop->args;
 		varg = prop->varg;
@@ -688,6 +694,6 @@
 	while (parg_n != NULL) {
 		if (rarg_n == NULL) {
-			printf("Error: Too few arguments to function '");
-			symbol_print_fqn(run->program, proc_ar->proc_sym);
+			printf("Error: Too few arguments to '");
+			symbol_print_fqn(outer_symbol);
 			printf("'.\n");
 			exit(1);
@@ -752,6 +758,6 @@
 	/* Check for excess real parameters. */
 	if (rarg_n != NULL) {
-		printf("Error: Too many arguments to function '");
-		symbol_print_fqn(run->program, proc_ar->proc_sym);
+		printf("Error: Too many arguments to '");
+		symbol_print_fqn(outer_symbol);
 		printf("'.\n");
 		exit(1);
@@ -775,9 +781,10 @@
 
 	/* AR should have been created with run_proc_ar_create(). */
-	assert(proc_ar->proc_sym != NULL);
-
-	/* The procedure being activated should be a property setter. */
-	prop = symbol_to_prop(proc_ar->proc_sym);
+	assert(proc_ar->proc != NULL);
+
+	/* The procedure being activated should belong to a property setter. */
+	prop = symbol_to_prop(proc_ar->proc->outer_symbol);
 	assert(prop != NULL);
+	assert(proc_ar->proc == prop->setter);
 
 	/* Fetch first block activation record. */
@@ -792,5 +799,5 @@
 
 	/* Declare variable using name of formal argument. */
-	intmap_set(&block_ar->vars, prop->setter_arg_name->sid, var);
+	intmap_set(&block_ar->vars, prop->setter_arg->name->sid, var);
 }
 
@@ -806,5 +813,5 @@
 		printf(" * ");
 		proc_ar = list_node_data(node, run_proc_ar_t *);
-		symbol_print_fqn(run->program, proc_ar->proc_sym);
+		symbol_print_fqn(proc_ar->proc->outer_symbol);
 		printf("\n");
 
@@ -844,4 +851,69 @@
 }
 
+/** Get item var-class.
+ *
+ * Get var-class of @a item, regardless whether it is a value or address.
+ * (I.e. the var class of the value or variable at the given address).
+ */
+var_class_t run_item_get_vc(run_t *run, rdata_item_t *item)
+{
+	var_class_t vc;
+	rdata_var_t *tpos;
+
+	(void) run;
+
+	switch (item->ic) {
+	case ic_value:
+		vc = item->u.value->var->vc;
+		break;
+	case ic_address:
+		switch (item->u.address->ac) {
+		case ac_var:
+			vc = item->u.address->u.var_a->vref->vc;
+			break;
+		case ac_prop:
+			/* Prefetch the value of the property. */
+			tpos = run_aprop_get_tpos(run, item->u.address);
+			vc = tpos->vc;
+			break;
+		default:
+			assert(b_false);
+		}
+		break;
+	default:
+		assert(b_false);
+	}
+
+	return vc;
+}
+
+/** Get pointer to current var node in temporary copy in property address.
+ *
+ * A property address refers to a specific @c var node in a property.
+ * This function will fetch a copy of the property value (by running
+ * its getter) if there is not a temporary copy in the address yet.
+ * It returns a pointer to the relevant @c var node in the temporary
+ * copy.
+ *
+ * @param run	Runner object.
+ * @param addr	Address of class @c ac_prop.
+ * @param	Pointer to var node.
+ */
+static rdata_var_t *run_aprop_get_tpos(run_t *run, rdata_address_t *addr)
+{
+	rdata_item_t *ritem;
+
+	assert(addr->ac == ac_prop);
+
+	if (addr->u.prop_a->tvalue == NULL) {
+		/* Fetch value of the property. */
+		run_address_read(run, addr, &ritem);
+		assert(ritem->ic == ic_value);
+		addr->u.prop_a->tvalue = ritem->u.value;
+		addr->u.prop_a->tpos = addr->u.prop_a->tvalue->var;
+	}
+
+	return addr->u.prop_a->tpos;
+}
 
 /** Read data from an address.
@@ -894,4 +966,6 @@
 
 	run_proc_ar_t *proc_ar;
+
+	rdata_var_t *cvar;
 
 #ifdef DEBUG_RUN_TRACE
@@ -903,6 +977,10 @@
 	 */
 	if (addr_prop->tvalue != NULL) {
-		printf("Unimplemented: Property field access.\n");
-		exit(1);
+		/* Copy the value */
+		rdata_var_copy(addr_prop->tpos, &cvar);
+		*ritem = rdata_item_new(ic_value);
+		(*ritem)->u.value = rdata_value_new();
+		(*ritem)->u.value->var = cvar;
+		return;
 	}
 
@@ -917,5 +995,5 @@
 	assert(prop != NULL);
 
-	if (prop->getter_body == NULL) {
+	if (prop->getter == NULL) {
 		printf("Error: Property is not readable.\n");
 		exit(1);
@@ -923,5 +1001,5 @@
 
 	/* Create procedure activation record. */
-	run_proc_ar_create(run, obj, prop_sym, prop->getter_body, &proc_ar);
+	run_proc_ar_create(run, obj, prop->getter, &proc_ar);
 
 	/* Fill in arguments (indices). */
@@ -973,5 +1051,5 @@
 	assert(prop != NULL);
 
-	if (prop->setter_body == NULL) {
+	if (prop->setter == NULL) {
 		printf("Error: Property is not writable.\n");
 		exit(1);
@@ -982,5 +1060,5 @@
 
 	/* Create procedure activation record. */
-	run_proc_ar_create(run, obj, prop_sym, prop->setter_body, &proc_ar);
+	run_proc_ar_create(run, obj, prop->setter, &proc_ar);
 
 	/* Fill in arguments (indices). */
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -48,7 +48,8 @@
 void run_proc_ar_set_setter_arg(run_t *run, run_proc_ar_t *proc_ar,
     rdata_item_t *arg_val);
-void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_symbol_t *proc_sym,
-    stree_block_t *proc_block, run_proc_ar_t **rproc_ar);
+void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
+    run_proc_ar_t **rproc_ar);
 
+var_class_t run_item_get_vc(run_t *run, rdata_item_t *item);
 void run_cvt_value_item(run_t *run, rdata_item_t *item, rdata_item_t **ritem);
 void run_address_read(run_t *run, rdata_address_t *address,
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run_expr.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -43,4 +43,5 @@
 #include "stree.h"
 #include "strtab.h"
+#include "tdata.h"
 
 #include "run_expr.h"
@@ -72,7 +73,7 @@
 static void run_new(run_t *run, stree_new_t *new_op, rdata_item_t **res);
 static void run_new_array(run_t *run, stree_new_t *new_op,
-    rdata_titem_t *titem, rdata_item_t **res);
+    tdata_item_t *titem, rdata_item_t **res);
 static void run_new_object(run_t *run, stree_new_t *new_op,
-    rdata_titem_t *titem, rdata_item_t **res);
+    tdata_item_t *titem, rdata_item_t **res);
 
 static void run_access(run_t *run, stree_access_t *access, rdata_item_t **res);
@@ -199,5 +200,5 @@
 		assert(csi != NULL);
 	} else {
-		csi = proc_ar->proc_sym->outer_csi;
+		csi = proc_ar->proc->outer_symbol->outer_csi;
 		obj = NULL;
 	}
@@ -231,7 +232,7 @@
 			printf("Error: Cannot access non-static member "
 			    "function '");
-			symbol_print_fqn(run->program, sym);
+			symbol_print_fqn(sym);
 			printf("' from nested CSI '");
-			symbol_print_fqn(run->program, csi_sym);
+			symbol_print_fqn(csi_sym);
 			printf("'.\n");
 			exit(1);
@@ -267,7 +268,7 @@
 			printf("Error: Cannot access non-static member "
 			    "variable '");
-			symbol_print_fqn(run->program, sym);
+			symbol_print_fqn(sym);
 			printf("' from nested CSI '");
-			symbol_print_fqn(run->program, csi_sym);
+			symbol_print_fqn(csi_sym);
 			printf("'.\n");
 			exit(1);
@@ -632,5 +633,5 @@
 static void run_new(run_t *run, stree_new_t *new_op, rdata_item_t **res)
 {
-	rdata_titem_t *titem;
+	tdata_item_t *titem;
 
 #ifdef DEBUG_RUN_TRACE
@@ -638,5 +639,6 @@
 #endif
 	/* Evaluate type expression */
-	run_texpr(run, new_op->texpr, &titem);
+	run_texpr(run->program, run_get_current_csi(run), new_op->texpr,
+	    &titem);
 
 	switch (titem->tic) {
@@ -644,5 +646,5 @@
 		run_new_array(run, new_op, titem, res);
 		break;
-	case tic_tcsi:
+	case tic_tobject:
 		run_new_object(run, new_op, titem, res);
 		break;
@@ -656,7 +658,7 @@
 /** Create new array. */
 static void run_new_array(run_t *run, stree_new_t *new_op,
-    rdata_titem_t *titem, rdata_item_t **res)
-{
-	rdata_tarray_t *tarray;
+    tdata_item_t *titem, rdata_item_t **res)
+{
+	tdata_array_t *tarray;
 	rdata_array_t *array;
 	rdata_var_t *array_var;
@@ -744,5 +746,5 @@
 /** Create new object. */
 static void run_new_object(run_t *run, stree_new_t *new_op,
-    rdata_titem_t *titem, rdata_item_t **res)
+    tdata_item_t *titem, rdata_item_t **res)
 {
 	rdata_object_t *obj;
@@ -764,6 +766,6 @@
 
 	/* Lookup object CSI. */
-	assert(titem->tic == tic_tcsi);
-	csi = titem->u.tcsi->csi;
+	assert(titem->tic == tic_tobject);
+	csi = titem->u.tobject->csi;
 	csi_sym = csi_to_symbol(csi);
 
@@ -823,5 +825,5 @@
 	printf("Run access operation on pre-evaluated base.\n");
 #endif
-	vc = rdata_item_get_vc(arg);
+	vc = run_item_get_vc(run, arg);
 
 	switch (vc) {
@@ -883,5 +885,5 @@
 	if (member == NULL) {
 		printf("Error: CSI '");
-		symbol_print_fqn(run->program, deleg_v->sym);
+		symbol_print_fqn(deleg_v->sym);
 		printf("' has no member named '%s'.\n",
 		    strtab_get_str(access->member_name->sid));
@@ -936,5 +938,5 @@
 	if (member == NULL) {
 		printf("Error: Object of class '");
-		symbol_print_fqn(run->program, object->class_sym);
+		symbol_print_fqn(object->class_sym);
 		printf("' has no member named '%s'.\n",
 		    strtab_get_str(access->member_name->sid));
@@ -1030,5 +1032,5 @@
 #ifdef DEBUG_RUN_TRACE
 	printf("Call function '");
-	symbol_print_fqn(run->program, deleg_v->sym);
+	symbol_print_fqn(deleg_v->sym);
 	printf("'\n");
 #endif
@@ -1050,6 +1052,5 @@
 
 	/* Create procedure activation record. */
-	run_proc_ar_create(run, deleg_v->obj, deleg_v->sym, fun->body,
-	    &proc_ar);
+	run_proc_ar_create(run, deleg_v->obj, fun->proc, &proc_ar);
 
 	/* Fill in argument values. */
@@ -1080,5 +1081,5 @@
 	run_expr(run, index->base, &rbase);
 
-	vc = rdata_item_get_vc(rbase);
+	vc = run_item_get_vc(run, rbase);
 
 	/* Implicitly dereference. */
@@ -1089,5 +1090,5 @@
 	}
 
-	vc = rdata_item_get_vc(base_i);
+	vc = run_item_get_vc(run, base_i);
 
 	/* Evaluate arguments (indices). */
@@ -1224,5 +1225,4 @@
 	printf("Run object index operation.\n");
 #endif
-	(void) run;
 	(void) index;
 
@@ -1252,4 +1252,10 @@
 	indexer_sym = symbol_search_csi(run->program, obj_csi, indexer_ident);
 
+	if (indexer_sym == NULL) {
+		printf("Error: Accessing object which does not have an "
+		    "indexer.\n");
+		exit(1);
+	}
+
 	/* Construct delegate. */
 	object_d = rdata_deleg_new();
Index: uspace/app/sbi/src/run_t.h
===================================================================
--- uspace/app/sbi/src/run_t.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -54,9 +54,6 @@
 	struct rdata_var *obj;
 
-	/** Definition of function or property being invoked */
-	struct stree_symbol *proc_sym;
-
-	/** Main block of procedure being invoked */
-	struct stree_block *proc_block;
+	/** Procedure being invoked */
+	struct stree_proc *proc;
 
 	/** Block activation records */
Index: uspace/app/sbi/src/run_texpr.c
===================================================================
--- uspace/app/sbi/src/run_texpr.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run_texpr.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -29,36 +29,37 @@
 /** @file Evaluates type expressions. */
 
+#include <assert.h>
 #include <stdlib.h>
 #include "list.h"
 #include "mytypes.h"
-#include "rdata.h"
-#include "run.h"
 #include "symbol.h"
+#include "tdata.h"
 
 #include "run_texpr.h"
 
-static void run_taccess(run_t *run, stree_taccess_t *taccess,
-    rdata_titem_t **res);
-static void run_tindex(run_t *run, stree_tindex_t *tindex,
-    rdata_titem_t **res);
-static void run_tliteral(run_t *run, stree_tliteral_t *tliteral,
-    rdata_titem_t **res);
-static void run_tnameref(run_t *run, stree_tnameref_t *tnameref,
-    rdata_titem_t **res);
-
-void run_texpr(run_t *run, stree_texpr_t *texpr, rdata_titem_t **res)
+static void run_taccess(stree_program_t *prog, stree_csi_t *ctx,
+    stree_taccess_t *taccess, tdata_item_t **res);
+static void run_tindex(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tindex_t *tindex, tdata_item_t **res);
+static void run_tliteral(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tliteral_t *tliteral, tdata_item_t **res);
+static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tnameref_t *tnameref, tdata_item_t **res);
+
+void run_texpr(stree_program_t *prog, stree_csi_t *ctx, stree_texpr_t *texpr,
+    tdata_item_t **res)
 {
 	switch (texpr->tc) {
 	case tc_taccess:
-		run_taccess(run, texpr->u.taccess, res);
+		run_taccess(prog, ctx, texpr->u.taccess, res);
 		break;
 	case tc_tindex:
-		run_tindex(run, texpr->u.tindex, res);
+		run_tindex(prog, ctx, texpr->u.tindex, res);
 		break;
 	case tc_tliteral:
-		run_tliteral(run, texpr->u.tliteral, res);
+		run_tliteral(prog, ctx, texpr->u.tliteral, res);
 		break;
 	case tc_tnameref:
-		run_tnameref(run, texpr->u.tnameref, res);
+		run_tnameref(prog, ctx, texpr->u.tnameref, res);
 		break;
 	case tc_tapply:
@@ -69,11 +70,11 @@
 }
 
-static void run_taccess(run_t *run, stree_taccess_t *taccess,
-    rdata_titem_t **res)
+static void run_taccess(stree_program_t *prog, stree_csi_t *ctx,
+    stree_taccess_t *taccess, tdata_item_t **res)
 {
 	stree_symbol_t *sym;
-	rdata_titem_t *targ_i;
-	rdata_titem_t *titem;
-	rdata_tcsi_t *tcsi;
+	tdata_item_t *targ_i;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
 	stree_csi_t *base_csi;
 
@@ -82,19 +83,18 @@
 #endif
 	/* Evaluate base type. */
-	run_texpr(run, taccess->arg, &targ_i);
-
-	if (targ_i->tic != tic_tcsi) {
-		printf("Error: Using '.' with type which is not CSI.\n");
+	run_texpr(prog, ctx, taccess->arg, &targ_i);
+
+	if (targ_i->tic != tic_tobject) {
+		printf("Error: Using '.' with type which is not an object.\n");
 		exit(1);
 	}
 
 	/* Get base CSI. */
-	base_csi = targ_i->u.tcsi->csi;
-
-	sym = symbol_lookup_in_csi(run->program, base_csi,
-	    taccess->member_name);
+	base_csi = targ_i->u.tobject->csi;
+
+	sym = symbol_lookup_in_csi(prog, base_csi, taccess->member_name);
 	if (sym->sc != sc_csi) {
 		printf("Error: Symbol '");
-		symbol_print_fqn(run->program, sym);
+		symbol_print_fqn(sym);
 		printf("' is not a CSI.\n");
 		exit(1);
@@ -102,18 +102,20 @@
 
 	/* Construct type item. */
-	titem = rdata_titem_new(tic_tcsi);
-	tcsi = rdata_tcsi_new();
-	titem->u.tcsi = tcsi;
-
-	tcsi->csi = sym->u.csi;
-
-	*res = titem;
-}
-
-static void run_tindex(run_t *run, stree_tindex_t *tindex, rdata_titem_t **res)
-{
-	rdata_titem_t *base_ti;
-	rdata_titem_t *titem;
-	rdata_tarray_t *tarray;
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = sym->u.csi;
+
+	*res = titem;
+}
+
+static void run_tindex(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tindex_t *tindex, tdata_item_t **res)
+{
+	tdata_item_t *base_ti;
+	tdata_item_t *titem;
+	tdata_array_t *tarray;
 	stree_expr_t *arg_expr;
 	list_node_t *arg_node;
@@ -123,9 +125,9 @@
 #endif
 	/* Evaluate base type. */
-	run_texpr(run, tindex->base_type, &base_ti);
-
-	/* Construct type item. */
-	titem = rdata_titem_new(tic_tarray);
-	tarray = rdata_tarray_new();
+	run_texpr(prog, ctx, tindex->base_type, &base_ti);
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tarray);
+	tarray = tdata_array_new();
 	titem->u.tarray = tarray;
 
@@ -146,20 +148,26 @@
 }
 
-static void run_tliteral(run_t *run, stree_tliteral_t *tliteral,
-    rdata_titem_t **res)
-{
-	rdata_titem_t *titem;
-	rdata_tprimitive_t *tprimitive;
+static void run_tliteral(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tliteral_t *tliteral, tdata_item_t **res)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+	tprimitive_class_t tpc;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Evaluating type literal.\n");
 #endif
-
-	(void) run;
+	(void) prog;
+	(void) ctx;
 	(void) tliteral;
 
-	/* Construct type item. */
-	titem = rdata_titem_new(tic_tprimitive);
-	tprimitive = rdata_tprimitive_new();
+	switch (tliteral->tlc) {
+	case tlc_int: tpc = tpc_int; break;
+	case tlc_string: tpc = tpc_string; break;
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc);
 	titem->u.tprimitive = tprimitive;
 
@@ -167,21 +175,19 @@
 }
 
-static void run_tnameref(run_t *run, stree_tnameref_t *tnameref,
-    rdata_titem_t **res)
-{
-	stree_csi_t *current_csi;
+static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tnameref_t *tnameref, tdata_item_t **res)
+{
 	stree_symbol_t *sym;
-	rdata_titem_t *titem;
-	rdata_tcsi_t *tcsi;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Evaluating type name reference.\n");
 #endif
-	current_csi = run_get_current_csi(run);
-	sym = symbol_lookup_in_csi(run->program, current_csi, tnameref->name);
+	sym = symbol_lookup_in_csi(prog, ctx, tnameref->name);
 
 	if (sym->sc != sc_csi) {
 		printf("Error: Symbol '");
-		symbol_print_fqn(run->program, sym);
+		symbol_print_fqn(sym);
 		printf("' is not a CSI.\n");
 		exit(1);
@@ -189,10 +195,11 @@
 
 	/* Construct type item. */
-	titem = rdata_titem_new(tic_tcsi);
-	tcsi = rdata_tcsi_new();
-	titem->u.tcsi = tcsi;
-
-	tcsi->csi = sym->u.csi;
-
-	*res = titem;
-}
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = sym->u.csi;
+
+	*res = titem;
+}
Index: uspace/app/sbi/src/run_texpr.h
===================================================================
--- uspace/app/sbi/src/run_texpr.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/run_texpr.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -32,5 +32,6 @@
 #include "mytypes.h"
 
-void run_texpr(run_t *run, stree_texpr_t *texpr, rdata_titem_t **res);
+void run_texpr(stree_program_t *prog, stree_csi_t *ctx, stree_texpr_t *texpr,
+    tdata_item_t **res);
 
 #endif
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/stree.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -136,4 +136,17 @@
 }
 
+stree_proc_t *stree_proc_new(void)
+{
+	stree_proc_t *proc;
+
+	proc = calloc(1, sizeof(stree_proc_t));
+	if (proc == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc;
+}
+
 stree_proc_arg_t *stree_proc_arg_new(void)
 {
@@ -507,5 +520,5 @@
 }
 
-stree_tliteral_t *stree_tliteral_new(void)
+stree_tliteral_t *stree_tliteral_new(tliteral_class_t tlc)
 {
 	stree_tliteral_t *tliteral;
@@ -517,4 +530,5 @@
 	}
 
+	tliteral->tlc = tlc;
 	return tliteral;
 }
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/stree.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -40,4 +40,5 @@
 stree_prop_t *stree_prop_new(void);
 
+stree_proc_t *stree_proc_new(void);
 stree_proc_arg_t *stree_proc_arg_new(void);
 stree_arg_attr_t *stree_arg_attr_new(arg_attr_class_t aac);
@@ -73,5 +74,5 @@
 stree_tapply_t *stree_tapply_new(void);
 stree_tindex_t *stree_tindex_new(void);
-stree_tliteral_t *stree_tliteral_new(void);
+stree_tliteral_t *stree_tliteral_new(tliteral_class_t tlc);
 stree_tnameref_t *stree_tnameref_new(void);
 
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/stree_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -82,7 +82,4 @@
 /** Binary operation class */
 typedef enum {
-	bo_period,
-	bo_slash,
-	bo_sbr,
 	bo_equal,
 	bo_notequal,
@@ -178,4 +175,6 @@
 	expr_class_t ec;
 
+	struct tdata_item *titem;
+
 	union {
 		stree_nameref_t *nameref;
@@ -379,6 +378,20 @@
 } stree_proc_arg_t;
 
+/** Procedure
+ *
+ * Procedure is the common term for a getter, setter or function body.
+ * A procedure can be invoked. However, the arguments are specified by
+ * the containing symbol.
+ */
+typedef struct stree_proc {
+	/** Symbol (function or property) containing the procedure */
+	struct stree_symbol *outer_symbol;
+
+	/** Main block */
+	stree_block_t *body;
+} stree_proc_t;
+
 /** Member function declaration */
-typedef struct {
+typedef struct stree_fun {
 	/** Function name */
 	stree_ident_t *name;
@@ -396,10 +409,10 @@
 	stree_texpr_t *rtype;
 
-	/** Function body */
-	stree_block_t *body;
+	/** Function implementation */
+	stree_proc_t *proc;
 } stree_fun_t;
 
 /** Member variable declaration */
-typedef struct {
+typedef struct stree_var {
 	stree_ident_t *name;
 	struct stree_symbol *symbol;
@@ -408,12 +421,13 @@
 
 /** Member property declaration */
-typedef struct {
+typedef struct stree_prop {
 	stree_ident_t *name;
 	struct stree_symbol *symbol;
 	stree_texpr_t *type;
 
-	stree_block_t *getter_body;
-	stree_ident_t *setter_arg_name;
-	stree_block_t *setter_body;
+	stree_proc_t *getter;
+
+	stree_proc_t *setter;
+	stree_proc_arg_t *setter_arg;
 
 	/** Formal parameters (for indexed properties) */
@@ -425,5 +439,6 @@
 
 /**
- * Fake identifier used with indexed properties. (Mostly for error messages.)
+ * Fake identifiers used with symbols that do not really have one.
+ * (Mostly for error messages.)
  */
 #define INDEXER_IDENT "$indexer"
@@ -504,5 +519,9 @@
 } symbol_class_t;
 
-/** Symbol */
+/** Symbol
+ *
+ * A symbol is a common superclass of different program elements that
+ * allow us to refer to them, print their fully qualified names, etc.
+ */
 typedef struct stree_symbol {
 	symbol_class_t sc;
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/stype.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file Implements a walk on the program that computes and checks static
+ * types. 'Types' the program.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "debug.h"
+#include "intmap.h"
+#include "list.h"
+#include "mytypes.h"
+#include "run_texpr.h"
+#include "stree.h"
+#include "strtab.h"
+#include "stype_expr.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "stype.h"
+
+static void stype_csi(stype_t *stype, stree_csi_t *csi);
+static void stype_fun(stype_t *stype, stree_fun_t *fun);
+static void stype_var(stype_t *stype, stree_var_t *var);
+static void stype_prop(stype_t *stype, stree_prop_t *prop);
+
+static void stype_block(stype_t *stype, stree_block_t *block);
+static void stype_stat(stype_t *stype, stree_stat_t *stat);
+
+static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s);
+static void stype_if(stype_t *stype, stree_if_t *if_s);
+static void stype_while(stype_t *stype, stree_while_t *while_s);
+static void stype_for(stype_t *stype, stree_for_t *for_s);
+static void stype_raise(stype_t *stype, stree_raise_t *raise_s);
+static void stype_return(stype_t *stype, stree_return_t *return_s);
+static void stype_exps(stype_t *stype, stree_exps_t *exp_s);
+static void stype_wef(stype_t *stype, stree_wef_t *wef_s);
+
+static tdata_item_t *stype_boolean_titem(stype_t *stype);
+
+/** Type module */
+void stype_module(stype_t *stype, stree_module_t *module)
+{
+	list_node_t *mbr_n;
+	stree_modm_t *mbr;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type module.\n");
+#endif
+	stype->current_csi = NULL;
+	stype->proc_vr = NULL;
+
+	mbr_n = list_first(&module->members);
+	while (mbr_n != NULL) {
+		mbr = list_node_data(mbr_n, stree_modm_t *);
+		assert(mbr->mc == mc_csi);
+
+		stype_csi(stype, mbr->u.csi);
+
+		mbr_n = list_next(&module->members, mbr_n);
+	}
+}
+
+/** Type CSI */
+static void stype_csi(stype_t *stype, stree_csi_t *csi)
+{
+	list_node_t *csimbr_n;
+	stree_csimbr_t *csimbr;
+	stree_csi_t *prev_ctx;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type CSI '");
+	symbol_print_fqn(csi_to_symbol(csi));
+	printf("'.\n");
+#endif
+	prev_ctx = stype->current_csi;
+	stype->current_csi = csi;
+
+	csimbr_n = list_first(&csi->members);
+	while (csimbr_n != NULL) {
+		csimbr = list_node_data(csimbr_n, stree_csimbr_t *);
+
+		switch (csimbr->cc) {
+		case csimbr_csi: stype_csi(stype, csimbr->u.csi); break;
+		case csimbr_fun: stype_fun(stype, csimbr->u.fun); break;
+		case csimbr_var: stype_var(stype, csimbr->u.var); break;
+		case csimbr_prop: stype_prop(stype, csimbr->u.prop); break;
+		}
+
+		csimbr_n = list_next(&csi->members, csimbr_n);
+	}
+
+	stype->current_csi = prev_ctx;
+}
+
+/** Type function */
+static void stype_fun(stype_t *stype, stree_fun_t *fun)
+{
+	list_node_t *arg_n;
+	stree_proc_arg_t *arg;
+	stree_symbol_t *fun_sym;
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type function '");
+	symbol_print_fqn(fun_to_symbol(fun));
+	printf("'.\n");
+#endif
+	fun_sym = fun_to_symbol(fun);
+
+	/*
+	 * Type formal arguments.
+	 * XXX Save the results.
+	 */
+	arg_n = list_first(&fun->args);
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_proc_arg_t *);
+
+		/* XXX Because of overloaded builtin WriteLine. */
+		if (arg->type == NULL) {
+			arg_n = list_next(&fun->args, arg_n);
+			continue;
+		}
+
+		run_texpr(stype->program, fun_sym->outer_csi, arg->type,
+		    &titem);
+
+		arg_n = list_next(&fun->args, arg_n);
+	}
+
+	/* Variadic argument */
+	if (fun->varg != NULL) {
+		/* Check type and verify it is an array. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->varg->type,
+		    &titem);
+
+		if (titem->tic != tic_tarray) {
+			printf("Error: Packed argument is not an array.\n");
+			exit(1);
+		}
+	}
+
+	/*
+	 * Type function body.
+	 */
+
+	/* Builtin functions do not have a body. */
+	if (fun->proc->body == NULL)
+		return;
+
+	stype->proc_vr = stype_proc_vr_new();
+	stype->proc_vr->proc = fun->proc;
+	list_init(&stype->proc_vr->block_vr);
+
+	stype_block(stype, fun->proc->body);
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
+}
+
+/** Type member variable */
+static void stype_var(stype_t *stype, stree_var_t *var)
+{
+	(void) stype;
+	(void) var;
+}
+
+/** Type property */
+static void stype_prop(stype_t *stype, stree_prop_t *prop)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type property '");
+	symbol_print_fqn(prop_to_symbol(prop));
+	printf("'.\n");
+#endif
+	stype->proc_vr = stype_proc_vr_new();
+	list_init(&stype->proc_vr->block_vr);
+
+	if (prop->getter != NULL) {
+		stype->proc_vr->proc = prop->getter;
+		stype_block(stype, prop->getter->body);
+	}
+
+	if (prop->setter != NULL) {
+		stype->proc_vr->proc = prop->setter;
+		stype_block(stype, prop->setter->body);
+	}
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
+}
+
+/** Type statement block */
+static void stype_block(stype_t *stype, stree_block_t *block)
+{
+	stree_stat_t *stat;
+	list_node_t *stat_n;
+	stype_block_vr_t *block_vr;
+	list_node_t *bvr_n;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type block.\n");
+#endif
+
+	/* Create block visit record. */
+	block_vr = stype_block_vr_new();
+	intmap_init(&block_vr->vdecls);
+
+	/* Add block visit record to the stack. */
+	list_append(&stype->proc_vr->block_vr, block_vr);
+
+	stat_n = list_first(&block->stats);
+	while (stat_n != NULL) {
+		stat = list_node_data(stat_n, stree_stat_t *);
+		stype_stat(stype, stat);
+
+		stat_n = list_next(&block->stats, stat_n);
+	}
+
+	/* Remove block visit record from the stack, */
+	bvr_n = list_last(&stype->proc_vr->block_vr);
+	assert(list_node_data(bvr_n, stype_block_vr_t *) == block_vr);
+	list_remove(&stype->proc_vr->block_vr, bvr_n);
+}
+
+/** Type statement */
+static void stype_stat(stype_t *stype, stree_stat_t *stat)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type statement.\n");
+#endif
+	switch (stat->sc) {
+	case st_vdecl: stype_vdecl(stype, stat->u.vdecl_s); break;
+	case st_if: stype_if(stype, stat->u.if_s); break;
+	case st_while: stype_while(stype, stat->u.while_s); break;
+	case st_for: stype_for(stype, stat->u.for_s); break;
+	case st_raise: stype_raise(stype, stat->u.raise_s); break;
+	case st_return: stype_return(stype, stat->u.return_s); break;
+	case st_exps: stype_exps(stype, stat->u.exp_s); break;
+	case st_wef: stype_wef(stype, stat->u.wef_s); break;
+	}
+}
+
+/** Type local variable declaration */
+static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s)
+{
+	stype_block_vr_t *block_vr;
+	stree_vdecl_t *old_vdecl;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type variable declaration statement.\n");
+#endif
+	block_vr = stype_get_current_block_vr(stype);
+	old_vdecl = (stree_vdecl_t *) intmap_get(&block_vr->vdecls,
+	    vdecl_s->name->sid);
+
+	if (old_vdecl != NULL) {
+		printf("Error: Duplicate variable declaration '%s'.\n",
+		    strtab_get_str(vdecl_s->name->sid));
+		exit(1);
+	}
+
+	intmap_set(&block_vr->vdecls, vdecl_s->name->sid, vdecl_s);
+
+}
+
+/** Type @c if statement */
+static void stype_if(stype_t *stype, stree_if_t *if_s)
+{
+	stree_expr_t *ccond;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'if' statement.\n");
+#endif
+	/* Convert condition to boolean type. */
+	stype_expr(stype, if_s->cond);
+	ccond = stype_convert(stype, if_s->cond, stype_boolean_titem(stype));
+
+	/* Patch code with augmented expression. */
+	if_s->cond = ccond;
+
+	/* Type the @c if block */
+	stype_block(stype, if_s->if_block);
+
+	/* Type the @c else block */
+	if (if_s->else_block != NULL)
+		stype_block(stype, if_s->else_block);
+}
+
+/** Type @c while statement */
+static void stype_while(stype_t *stype, stree_while_t *while_s)
+{
+	stree_expr_t *ccond;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'while' statement.\n");
+#endif
+	/* Convert condition to boolean type. */
+	stype_expr(stype, while_s->cond);
+	ccond = stype_convert(stype, while_s->cond,
+	    stype_boolean_titem(stype));
+
+	/* Patch code with augmented expression. */
+	while_s->cond = ccond;
+
+	/* Type the body of the loop */
+	stype_block(stype, while_s->body);
+}
+
+/** Type @c for statement */
+static void stype_for(stype_t *stype, stree_for_t *for_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'for' statement.\n");
+#endif
+	stype_block(stype, for_s->body);
+}
+
+/** Type @c raise statement */
+static void stype_raise(stype_t *stype, stree_raise_t *raise_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'raise' statement.\n");
+#endif
+	stype_expr(stype, raise_s->expr);
+}
+
+/** Type @c return statement */
+static void stype_return(stype_t *stype, stree_return_t *return_s)
+{
+	stree_symbol_t *outer_sym;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+
+	stree_expr_t *cexpr;
+	tdata_item_t *dtype;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'return' statement.\n");
+#endif
+	stype_expr(stype, return_s->expr);
+
+	/* Determine the type we need to return. */
+
+	outer_sym = stype->proc_vr->proc->outer_symbol;
+	switch (outer_sym->sc) {
+	case sc_fun:
+		fun = symbol_to_fun(outer_sym);
+		assert(fun != NULL);
+
+		/* XXX Memoize to avoid recomputing. */
+		run_texpr(stype->program, outer_sym->outer_csi, fun->rtype,
+		    &dtype);
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_sym);
+		assert(prop != NULL);
+
+		if (stype->proc_vr->proc != prop->getter) {
+			printf("Error: Return statement in "
+			    "setter.\n");
+			exit(1);
+		}
+
+		/* XXX Memoize to avoid recomputing. */
+		run_texpr(stype->program, outer_sym->outer_csi, prop->type,
+		    &dtype);
+		break;
+	default:
+		assert(b_false);
+	}
+
+	/* Convert to the return type. */
+	cexpr = stype_convert(stype, return_s->expr, dtype);
+
+	/* Patch code with the augmented expression. */
+	return_s->expr = cexpr;
+}
+
+/** Type expression statement */
+static void stype_exps(stype_t *stype, stree_exps_t *exp_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type expression statement.\n");
+#endif
+	stype_expr(stype, exp_s->expr);
+
+	if (exp_s->expr->titem != NULL)
+		printf("Warning: Expression value ignored.\n");
+}
+
+/** Type With-Except-Finally statement */
+static void stype_wef(stype_t *stype, stree_wef_t *wef_s)
+{
+	list_node_t *ec_n;
+	stree_except_t *ec;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type WEF statement.\n");
+#endif
+	/* Type the @c with block. */
+	if (wef_s->with_block != NULL)
+		stype_block(stype, wef_s->with_block);
+
+	/* Type the @c except clauses. */
+	ec_n = list_first(&wef_s->except_clauses);
+	while (ec_n != NULL) {
+		ec = list_node_data(ec_n, stree_except_t *);
+		stype_block(stype, ec->block);
+
+		ec_n = list_next(&wef_s->except_clauses, ec_n);
+	}
+
+	/* Type the @c finally block. */
+	if (wef_s->finally_block != NULL)
+		stype_block(stype, wef_s->finally_block);
+}
+
+/** Convert expression of one type to another type.
+ *
+ * If the type of expression @a expr is not compatible with @a dtype
+ * (i.e. there does not exist an implicit conversion from @a expr->type to
+ * @a dtype), this function will produce an error (Cannot convert A to B).
+ *
+ * Otherwise it will either return the expression unmodified (if there is
+ * no action to take at run time) or it will return a new expression
+ * while clobbering the old one. Typically this would just attach the
+ * expression as a subtree of the conversion.
+ *
+ * Note: No conversion that would require modifying @a expr is implemented
+ * yet.
+ */
+stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+
+	(void) stype;
+	src = expr->titem;
+
+	if (dest == NULL) {
+		printf("Error: Conversion destination is not valid.\n");
+		exit(1);
+	}
+
+	if (src == NULL) {
+		printf("Error: Conversion source is not valid.\n");
+		exit(1);
+	}
+
+	if (dest == NULL || src == NULL)
+		return expr;
+
+	/*
+	 * Special case: Nil to object.
+	 */
+	if (src->tic == tic_tprimitive && src->u.tprimitive->tpc == tpc_nil) {
+		if (dest->tic == tic_tobject)
+			return expr;
+	}
+
+	if (src->tic != dest->tic)
+		goto failure;
+
+	switch (src->tic) {
+	case tic_tprimitive:
+		/* Check if both have the same tprimitive class. */
+		if (src->u.tprimitive->tpc != dest->u.tprimitive->tpc)
+			goto failure;
+		break;
+	case tic_tobject:
+		/* Check if @c src is derived from @c dest. */
+		if (stree_is_csi_derived_from_csi(src->u.tobject->csi,
+		    dest->u.tobject->csi) != b_true) {
+			goto failure;
+		}
+		break;
+	case tic_tarray:
+		/* Compare rank and base type. */
+		if (src->u.tarray->rank != dest->u.tarray->rank)
+			goto failure;
+
+		/* XXX Should we convert each element? */
+		if (tdata_item_equal(src->u.tarray->base_ti,
+		    dest->u.tarray->base_ti) != b_true)
+			goto failure;
+		break;
+	default:
+		printf("Error: Unimplemented: Converting '");
+		tdata_item_print(src);
+		printf("' to '");
+		tdata_item_print(dest);
+		printf("'.\n");
+		exit(1);
+	}
+
+	return expr;
+
+failure:
+	printf("Error: Cannot convert ");
+	tdata_item_print(src);
+	printf(" to ");
+	tdata_item_print(dest);
+	printf(".\n");
+
+	/* XXX We should rather return a bogus expression of type @a dest */
+	exit(1);
+}
+
+/** Return a boolean type item */
+static tdata_item_t *stype_boolean_titem(stype_t *stype)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+
+	(void) stype;
+
+	/* XXX Use a true boolean type */
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc_int);
+	titem->u.tprimitive = tprimitive;
+
+	return titem;
+}
+
+/** Find a local variable in the current function. */
+stree_vdecl_t *stype_local_vars_lookup(stype_t *stype, sid_t name)
+{
+	stype_proc_vr_t *proc_vr;
+	stype_block_vr_t *block_vr;
+	stree_vdecl_t *vdecl;
+	list_node_t *node;
+
+	proc_vr = stype->proc_vr;
+	node = list_last(&proc_vr->block_vr);
+
+	/* Walk through all block visit records. */
+	while (node != NULL) {
+		block_vr = list_node_data(node, stype_block_vr_t *);
+		vdecl = intmap_get(&block_vr->vdecls, name);
+		if (vdecl != NULL)
+			return vdecl;
+
+		node = list_prev(&proc_vr->block_vr, node);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Find argument of the current procedure. */
+stree_proc_arg_t *stype_proc_args_lookup(stype_t *stype, sid_t name)
+{
+	stype_proc_vr_t *proc_vr;
+
+	stree_symbol_t *outer_sym;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+
+	list_t *args;
+	list_node_t *arg_node;
+	stree_proc_arg_t *varg;
+	stree_proc_arg_t *arg;
+	stree_proc_arg_t *setter_arg;
+
+	proc_vr = stype->proc_vr;
+	outer_sym = proc_vr->proc->outer_symbol;
+
+	setter_arg = NULL;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Look for argument named '%s'.\n", strtab_get_str(name));
+#endif
+
+	switch (outer_sym->sc) {
+	case sc_fun:
+		fun = symbol_to_fun(outer_sym);
+		assert(fun != NULL);
+		args = &fun->args;
+		varg = fun->varg;
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(outer_sym);
+		assert(prop != NULL);
+		args = &prop->args;
+		varg = prop->varg;
+
+		/* If we are in a setter, look also at setter argument. */
+		if (prop->setter == proc_vr->proc)
+			setter_arg = prop->setter_arg;
+		break;
+	default:
+		assert(b_false);
+	}
+
+	arg_node = list_first(args);
+	while (arg_node != NULL) {
+		arg = list_node_data(arg_node, stree_proc_arg_t *);
+		if (arg->name->sid == name) {
+			/* Match */
+#ifdef DEBUG_TYPE_TRACE
+			printf("Found argument.\n");
+#endif
+			return arg;
+		}
+
+		arg_node = list_next(args, arg_node);
+	}
+
+	/* Variadic argument */
+	if (varg != NULL && varg->name->sid == name) {
+#ifdef DEBUG_TYPE_TRACE
+		printf("Found variadic argument.\n");
+#endif
+		return varg;
+}
+
+	/* Setter argument */
+	if (setter_arg != NULL && setter_arg->name->sid == name) {
+#ifdef DEBUG_TYPE_TRACE
+		printf("Found setter argument.\n");
+#endif
+		return setter_arg;
+
+	}
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Not found.\n");
+#endif
+	/* No match */
+	return NULL;
+}
+
+/** Get current block visit record. */
+stype_block_vr_t *stype_get_current_block_vr(stype_t *stype)
+{
+	list_node_t *node;
+
+	node = list_last(&stype->proc_vr->block_vr);
+	return list_node_data(node, stype_block_vr_t *);
+}
+
+stype_proc_vr_t *stype_proc_vr_new(void)
+{
+	stype_proc_vr_t *proc_vr;
+
+	proc_vr = calloc(1, sizeof(stype_proc_vr_t));
+	if (proc_vr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return proc_vr;
+}
+
+stype_block_vr_t *stype_block_vr_new(void)
+{
+	stype_block_vr_t *block_vr;
+
+	block_vr = calloc(1, sizeof(stype_block_vr_t));
+	if (block_vr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return block_vr;
+}
Index: uspace/app/sbi/src/stype.h
===================================================================
--- uspace/app/sbi/src/stype.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/stype.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_H_
+#define STYPE_H_
+
+#include "mytypes.h"
+
+void stype_module(stype_t *stype, stree_module_t *module);
+
+stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
+
+stree_vdecl_t *stype_local_vars_lookup(stype_t *stype, sid_t name);
+stree_proc_arg_t *stype_proc_args_lookup(stype_t *stype, sid_t name);
+stype_block_vr_t *stype_get_current_block_vr(stype_t *stype);
+
+stype_proc_vr_t *stype_proc_vr_new(void);
+stype_block_vr_t *stype_block_vr_new(void);
+
+#endif
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/stype_expr.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Type expressions. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "debug.h"
+#include "list.h"
+#include "mytypes.h"
+#include "run_texpr.h"
+#include "stree.h"
+#include "strtab.h"
+#include "stype.h"
+#include "symbol.h"
+#include "tdata.h"
+
+#include "stype_expr.h"
+
+static void stype_nameref(stype_t *stype, stree_nameref_t *nameref,
+    tdata_item_t **rtitem);
+static void stype_literal(stype_t *stype, stree_literal_t *literal,
+    tdata_item_t **rtitem);
+static void stype_self_ref(stype_t *stype, stree_self_ref_t *self_ref,
+    tdata_item_t **rtitem);
+
+static void stype_binop(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem);
+static void stype_binop_tprimitive(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+static void stype_binop_tobject(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+
+static void stype_unop(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t **rtitem);
+static void stype_new(stype_t *stype, stree_new_t *new,
+    tdata_item_t **rtitem);
+
+static void stype_access(stype_t *stype, stree_access_t *access,
+    tdata_item_t **rtitem);
+static void stype_access_tprimitive(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tobject(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tarray(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+static void stype_access_tgeneric(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem);
+
+static void stype_call(stype_t *stype, stree_call_t *call,
+    tdata_item_t **rtitem);
+
+static void stype_index(stype_t *stype, stree_index_t *index,
+    tdata_item_t **rtitem);
+static void stype_index_tprimitive(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tobject(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tarray(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+static void stype_index_tgeneric(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem);
+
+static void stype_assign(stype_t *stype, stree_assign_t *assign,
+    tdata_item_t **rtitem);
+
+
+/** Type expression. */
+void stype_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *et;
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type expression.\n");
+#endif
+	switch (expr->ec) {
+	case ec_nameref: stype_nameref(stype, expr->u.nameref, &et); break;
+	case ec_literal: stype_literal(stype, expr->u.literal, &et); break;
+	case ec_self_ref: stype_self_ref(stype, expr->u.self_ref, &et); break;
+	case ec_binop: stype_binop(stype, expr->u.binop, &et); break;
+	case ec_unop: stype_unop(stype, expr->u.unop, &et); break;
+	case ec_new: stype_new(stype, expr->u.new_op, &et); break;
+	case ec_access: stype_access(stype, expr->u.access, &et); break;
+	case ec_call: stype_call(stype, expr->u.call, &et); break;
+	case ec_index: stype_index(stype, expr->u.index, &et); break;
+	case ec_assign: stype_assign(stype, expr->u.assign, &et); break;
+	}
+
+	expr->titem = et;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Expression type is '");
+	tdata_item_print(et);
+	printf("'.\n");
+#endif
+}
+
+/** Type name reference. */
+static void stype_nameref(stype_t *stype, stree_nameref_t *nameref,
+    tdata_item_t **rtitem)
+{
+	stree_symbol_t *sym;
+	stree_vdecl_t *vdecl;
+	stree_proc_arg_t *proc_arg;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+	stree_csi_t *csi;
+	stree_fun_t *fun;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of name reference '%s'.\n",
+	    strtab_get_str(nameref->name->sid));
+#endif
+	/*
+	 * Look for a local variable declaration.
+	 */
+
+	vdecl = stype_local_vars_lookup(stype, nameref->name->sid);
+	if (vdecl != NULL) {
+		/* Found a local variable declaration. */
+#ifdef DEBUG_RUN_TRACE
+		printf("Found local variable declaration.\n");
+#endif
+		run_texpr(stype->program, stype->current_csi, vdecl->type,
+		    &titem);
+		*rtitem = titem;
+		return;
+	}
+
+	/*
+	 * Look for a procedure argument.
+	 */
+
+	proc_arg = stype_proc_args_lookup(stype, nameref->name->sid);
+	if (proc_arg != NULL) {
+		/* Found a procedure argument. */
+#ifdef DEBUG_RUN_TRACE
+		printf("Found procedure argument.\n");
+#endif
+		run_texpr(stype->program, stype->current_csi, proc_arg->type,
+		    &titem);
+		*rtitem = titem;
+		return;
+	}
+
+	/*
+	 * Look for a class-wide or global symbol.
+	 */
+
+	sym = symbol_lookup_in_csi(stype->program, stype->current_csi,
+	    nameref->name);
+
+	switch (sym->sc) {
+	case sc_var:
+		run_texpr(stype->program, stype->current_csi,
+		    sym->u.var->type, &titem);
+		break;
+	case sc_prop:
+		run_texpr(stype->program, stype->current_csi,
+		    sym->u.prop->type, &titem);
+		break;
+	case sc_csi:
+		csi = symbol_to_csi(sym);
+		assert(csi != NULL);
+
+		titem = tdata_item_new(tic_tobject);
+		tobject = tdata_object_new();
+		titem->u.tobject = tobject;
+
+		/* This is a static CSI reference. */
+		tobject->static_ref = b_true;
+		tobject->csi = csi;
+		break;
+	case sc_fun:
+		fun = symbol_to_fun(sym);
+		assert(fun != NULL);
+
+		titem = tdata_item_new(tic_tfun);
+		titem->u.tfun = tdata_fun_new();
+		titem->u.tfun->fun = fun;
+		break;
+	}
+
+	*rtitem = titem;
+}
+
+/** Type a literal. */
+static void stype_literal(stype_t *stype, stree_literal_t *literal,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+	tdata_primitive_t *tprimitive;
+	tprimitive_class_t tpc;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of literal.\n");
+#endif
+	(void) stype;
+
+	switch (literal->ltc) {
+	case ltc_int: tpc = tpc_int; break;
+	case ltc_ref: tpc = tpc_nil; break;
+	case ltc_string: tpc = tpc_string; break;
+	}
+
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc);
+	titem->u.tprimitive = tprimitive;
+
+	*rtitem = titem;
+}
+
+/** Type a self reference. */
+static void stype_self_ref(stype_t *stype, stree_self_ref_t *self_ref,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of self reference.\n");
+#endif
+	(void) stype;
+	(void) self_ref;
+
+	*rtitem = NULL;
+}
+
+/** Type a binary operation. */
+static void stype_binop(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t **rtitem)
+{
+	bool_t equal;
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of binary operation.\n");
+#endif
+	stype_expr(stype, binop->arg1);
+	stype_expr(stype, binop->arg2);
+
+	/* XXX This should be checked properly. */
+	assert(binop->arg1->titem != NULL);
+	assert(binop->arg2->titem != NULL);
+
+	if (binop->arg1->titem == NULL) {
+		/* XXX Make this an error when ready. */
+		printf("Error First binary operand has no value.\n");
+		exit(1);
+	}
+
+	if (binop->arg2->titem == NULL) {
+		/* XXX Make this an error when ready. */
+		printf("Error: Second binary operand has no value.\n");
+		exit(1);
+	}
+
+	equal = tdata_item_equal(binop->arg1->titem, binop->arg2->titem);
+	if (equal != b_true) {
+		printf("Error: Binary operation arguments "
+		    "have different types ('");
+		tdata_item_print(binop->arg1->titem);
+		printf("' and '");
+		tdata_item_print(binop->arg2->titem);
+		printf("').\n");
+		exit(1);
+	}
+
+	titem = binop->arg1->titem;
+
+	switch (titem->tic) {
+	case tic_tprimitive:
+		stype_binop_tprimitive(stype, binop, binop->arg1->titem,
+		    binop->arg2->titem, rtitem);
+		break;
+	case tic_tobject:
+		stype_binop_tobject(stype, binop, binop->arg1->titem,
+		    binop->arg2->titem, rtitem);
+		break;
+	default:
+		printf("Error: Binary operation on value which is not of a "
+		    "supported type (found '");
+		tdata_item_print(titem);
+		printf("').\n");
+		exit(1);
+	}
+
+}
+
+/** Type a binary operation arguments of primitive type. */
+static void stype_binop_tprimitive(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tprimitive_class_t rtpc;
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	assert(ta->tic == tic_tprimitive);
+	assert(tb->tic == tic_tprimitive);
+
+	switch (ta->u.tprimitive->tpc) {
+	case tpc_int:
+		rtpc = tpc_int;
+		break;
+	case tpc_nil:
+		printf("Unimplemented; Binary operation on nil.\n");
+		exit(1);
+	case tpc_string:
+		if (binop->bc != bo_plus) {
+			printf("Unimplemented: Binary operation(%d) "
+			    "on strings.\n", binop->bc);
+			exit(1);
+		}
+		rtpc = tpc_string;
+		break;
+	}
+
+	res_ti = tdata_item_new(tic_tprimitive);
+	res_ti->u.tprimitive = tdata_primitive_new(rtpc);
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation arguments of an object type. */
+static void stype_binop_tobject(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	(void) stype;
+
+	assert(ta->tic == tic_tobject || (ta->tic == tic_tprimitive &&
+	    ta->u.tprimitive->tpc == tpc_nil));
+	assert(tb->tic == tic_tobject || (tb->tic == tic_tprimitive &&
+	    tb->u.tprimitive->tpc == tpc_nil));
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparing objects -> boolean (XXX int for now) type */
+		res_ti = tdata_item_new(tic_tprimitive);
+		res_ti->u.tprimitive = tdata_primitive_new(tpc_int);
+		break;
+	default:
+		printf("Error: Binary operation (%d) on objects.\n",
+		    binop->bc);
+		res_ti = NULL;
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+
+/** Type a unary operation. */
+static void stype_unop(stype_t *stype, stree_unop_t *unop,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of unary operation.\n");
+#endif
+	stype_expr(stype, unop->arg);
+
+	*rtitem = NULL;
+}
+
+/** Type a @c new operation. */
+static void stype_new(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t **rtitem)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of 'new' operation.\n");
+#endif
+	/*
+	 * Type of @c new expression is exactly the type supplied as parameter
+	 * to the @c new operator.
+	 */
+	run_texpr(stype->program, stype->current_csi, new_op->texpr, rtitem);
+}
+
+/** Type a field access operation */
+static void stype_access(stype_t *stype, stree_access_t *access,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *arg_ti;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of access operation.\n");
+#endif
+	stype_expr(stype, access->arg);
+	arg_ti = access->arg->titem;
+
+	if (arg_ti == NULL) {
+		printf("Error: Argument of access has no value.\n");
+		exit(1);
+	}
+
+	switch (arg_ti->tic) {
+	case tic_tprimitive:
+		stype_access_tprimitive(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tobject:
+		stype_access_tobject(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tarray:
+		stype_access_tarray(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tgeneric:
+		stype_access_tgeneric(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tfun:
+		printf("Error: Using '.' operator on a function.\n");
+		exit(1);
+		break;
+	}
+}
+
+/** Type a primitive type access operation. */
+static void stype_access_tprimitive(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing primitive type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	exit(1);
+}
+
+/** Type an object access operation. */
+static void stype_access_tobject(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	stree_symbol_t *member_sym;
+	stree_var_t *var;
+	stree_fun_t *fun;
+	stree_prop_t *prop;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type a CSI access operation.\n");
+#endif
+	assert(arg_ti->tic == tic_tobject);
+	tobject = arg_ti->u.tobject;
+
+	/* Look for a member with the specified name. */
+	member_sym = symbol_search_csi(stype->program, tobject->csi,
+	    access->member_name);
+
+	if (member_sym == NULL) {
+		/* No such member found. */
+		printf("Error: CSI '");
+		symbol_print_fqn(csi_to_symbol(tobject->csi));
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	switch (member_sym->sc) {
+	case sc_csi:
+		printf("Error: Accessing object member which is nested "
+		    "CSI.\n");
+		exit(1);
+	case sc_fun:
+		fun = symbol_to_fun(member_sym);
+		assert(fun != NULL);
+		*rtitem = tdata_item_new(tic_tfun);
+		(*rtitem)->u.tfun = tdata_fun_new();
+		(*rtitem)->u.tfun->fun = fun;
+		break;
+	case sc_var:
+		var = symbol_to_var(member_sym);
+		assert(var != NULL);
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, member_sym->outer_csi,
+		    var->type, rtitem);
+		break;
+	case sc_prop:
+		prop = symbol_to_prop(member_sym);
+		assert(prop != NULL);
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, member_sym->outer_csi,
+		    prop->type, rtitem);
+		break;
+	}
+}
+
+/** Type an array access operation. */
+static void stype_access_tarray(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing array type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	exit(1);
+}
+
+/** Type a generic access operation. */
+static void stype_access_tgeneric(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) access;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Accessing generic type '");
+	tdata_item_print(arg_ti);
+	printf("'.\n");
+	exit(1);
+}
+
+/** Type a call operation. */
+static void stype_call(stype_t *stype, stree_call_t *call,
+    tdata_item_t **rtitem)
+{
+	list_node_t *farg_n;
+	stree_proc_arg_t *farg;
+	tdata_item_t *farg_ti;
+	tdata_item_t *varg_ti;
+
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	stree_expr_t *carg;
+
+	tdata_item_t *fun_ti;
+	stree_fun_t *fun;
+	stree_symbol_t *fun_sym;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of call operation.\n");
+#endif
+	/* Type the function */
+	stype_expr(stype, call->fun);
+
+	fun_ti = call->fun->titem;
+	assert(fun_ti->tic == tic_tfun);
+	fun = fun_ti->u.tfun->fun;
+	fun_sym = fun_to_symbol(fun);
+
+	/* Type and check the arguments. */
+	farg_n = list_first(&fun->args);
+	arg_n = list_first(&call->args);
+	while (farg_n != NULL && arg_n != NULL) {
+		farg = list_node_data(farg_n, stree_proc_arg_t *);
+		arg = list_node_data(arg_n, stree_expr_t *);
+		stype_expr(stype, arg);
+
+		/* XXX Because of overloaded bultin WriteLine */
+		if (farg->type == NULL) {
+			/* Skip the check */
+			farg_n = list_next(&fun->args, farg_n);
+			arg_n = list_next(&call->args, arg_n);
+			continue;
+		}
+
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, farg->type,
+		    &farg_ti);
+
+		/* Convert expression to type of formal argument. */
+		carg = stype_convert(stype, arg, farg_ti);
+
+		/* Patch code with augmented expression. */
+		list_node_setdata(arg_n, carg);
+
+		farg_n = list_next(&fun->args, farg_n);
+		arg_n = list_next(&call->args, arg_n);
+	}
+
+	/* Type and check variadic arguments. */
+	if (fun->varg != NULL) {
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->varg->type,
+		    &farg_ti);
+
+		/* Get array element type */
+		assert(farg_ti->tic == tic_tarray);
+		varg_ti = farg_ti->u.tarray->base_ti;
+
+		while (arg_n != NULL) {
+			arg = list_node_data(arg_n, stree_expr_t *);
+			stype_expr(stype, arg);
+
+			/* Convert expression to type of formal argument. */
+			carg = stype_convert(stype, arg, varg_ti);
+
+			/* Patch code with augmented expression. */
+			list_node_setdata(arg_n, carg);
+
+			arg_n = list_next(&call->args, arg_n);
+		}
+	}
+
+	if (farg_n != NULL) {
+		printf("Error: Too few arguments to function '");
+		symbol_print_fqn(fun_to_symbol(fun));
+		printf("'.\n");
+		exit(1);
+	}
+
+	if (arg_n != NULL) {
+		printf("Error: Too many arguments to function '");
+		symbol_print_fqn(fun_to_symbol(fun));
+		printf("'.\n");
+		exit(1);
+	}
+
+	if (fun->rtype != NULL) {
+		/* XXX Memoize to avoid recomputing every time. */
+		run_texpr(stype->program, fun_sym->outer_csi, fun->rtype,
+		    rtitem);
+	} else {
+		*rtitem = NULL;
+	}
+}
+
+/** Type an indexing operation. */
+static void stype_index(stype_t *stype, stree_index_t *index,
+    tdata_item_t **rtitem)
+{
+	tdata_item_t *base_ti;
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of index operation.\n");
+#endif
+	stype_expr(stype, index->base);
+	base_ti = index->base->titem;
+
+	/* Type the arguments (indices). */
+	arg_n = list_first(&index->args);
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_expr_t *);
+		stype_expr(stype, arg);
+
+		arg_n = list_next(&index->args, arg_n);
+	}
+
+	switch (base_ti->tic) {
+	case tic_tprimitive:
+		stype_index_tprimitive(stype, index, base_ti, rtitem);
+		break;
+	case tic_tobject:
+		stype_index_tobject(stype, index, base_ti, rtitem);
+		break;
+	case tic_tarray:
+		stype_index_tarray(stype, index, base_ti, rtitem);
+		break;
+	case tic_tgeneric:
+		stype_index_tgeneric(stype, index, base_ti, rtitem);
+		break;
+	case tic_tfun:
+		printf("Error: Indexing a function.\n");
+		exit(1);
+		break;
+	}
+}
+
+/** Type a primitive indexing operation. */
+static void stype_index_tprimitive(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	tdata_primitive_t *tprimitive;
+	tdata_item_t *titem;
+
+	(void) stype;
+	(void) index;
+
+	assert(base_ti->tic == tic_tprimitive);
+	tprimitive = base_ti->u.tprimitive;
+
+	if (tprimitive->tpc == tpc_string) {
+		titem = tdata_item_new(tic_tprimitive);
+		titem->u.tprimitive = tdata_primitive_new(tpc_int);
+		*rtitem = titem;
+		return;
+	}
+
+	printf("Error: Indexing primitive type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+	exit(1);
+}
+
+/** Type an object indexing operation. */
+static void stype_index_tobject(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	tdata_object_t *tobject;
+	stree_symbol_t *idx_sym;
+	stree_prop_t *idx;
+	stree_ident_t *idx_ident;
+
+	(void) index;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Indexing object type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+#endif
+
+	assert(base_ti->tic == tic_tobject);
+	tobject = base_ti->u.tobject;
+
+	/* Find indexer symbol. */
+	idx_ident = stree_ident_new();
+	idx_ident->sid = strtab_get_sid(INDEXER_IDENT);
+	idx_sym = symbol_search_csi(stype->program, tobject->csi, idx_ident);
+
+	if (idx_sym == NULL) {
+		printf("Error: Indexing object of type '");
+		tdata_item_print(base_ti);
+		printf("' which does not have an indexer.\n");
+		exit(1);
+	}
+
+	idx = symbol_to_prop(idx_sym);
+	assert(idx != NULL);
+
+	/* XXX Memoize to avoid recomputing every time. */
+	run_texpr(stype->program, idx_sym->outer_csi, idx->type, rtitem);
+}
+
+/** Type an array indexing operation. */
+static void stype_index_tarray(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	int arg_count;
+
+	(void) stype;
+	assert(base_ti->tic == tic_tarray);
+
+	/*
+	 * Check that type of all indices is @c int and that the number of
+	 * indices matches array rank.
+	 */
+	arg_count = 0;
+	arg_n = list_first(&index->args);
+	while (arg_n != NULL) {
+		++arg_count;
+
+		arg = list_node_data(arg_n, stree_expr_t *);
+		if (arg->titem->tic != tic_tprimitive ||
+		    arg->titem->u.tprimitive->tpc != tpc_int) {
+
+			printf("Error: Array index is not an integer.\n");
+			exit(1);
+		}
+
+		arg_n = list_next(&index->args, arg_n);
+	}
+
+	if (arg_count != base_ti->u.tarray->rank) {
+		printf("Error: Using %d indices with array of rank %d.\n",
+		    arg_count, base_ti->u.tarray->rank);
+		exit(1);
+	}
+
+	*rtitem = base_ti->u.tarray->base_ti;
+}
+
+/** Type a generic indexing operation. */
+static void stype_index_tgeneric(stype_t *stype, stree_index_t *index,
+    tdata_item_t *base_ti, tdata_item_t **rtitem)
+{
+	(void) stype;
+	(void) index;
+	(void) rtitem;
+
+	printf("Error: Unimplemented: Indexing generic type '");
+	tdata_item_print(base_ti);
+	printf("'.\n");
+	exit(1);
+}
+
+/** Type an assignment. */
+static void stype_assign(stype_t *stype, stree_assign_t *assign,
+    tdata_item_t **rtitem)
+{
+	stree_expr_t *csrc;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of assignment.\n");
+#endif
+	stype_expr(stype, assign->dest);
+	stype_expr(stype, assign->src);
+
+	csrc = stype_convert(stype, assign->src, assign->dest->titem);
+
+	/* Patch code with the augmented expression. */
+	assign->src = csrc;
+	*rtitem = NULL;
+}
Index: uspace/app/sbi/src/stype_expr.h
===================================================================
--- uspace/app/sbi/src/stype_expr.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/stype_expr.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_EXPR_H_
+#define STYPE_EXPR_H_
+
+#include "mytypes.h"
+
+void stype_expr(stype_t *stype, stree_expr_t *expr);
+
+#endif
Index: uspace/app/sbi/src/stype_t.h
===================================================================
--- uspace/app/sbi/src/stype_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/stype_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef STYPE_T_H_
+#define STYPE_T_H_
+
+/** Block visit record
+ *
+ * One block VR is created for each block that we enter. A variable declaration
+ * statement inserts the variable declaration here. Upon leaving the block we
+ * pop from the stack, thus all the variable declarations from that block
+ * are forgotten.
+ */
+typedef struct run_block_vr {
+	/** Variable declarations in this block */
+	intmap_t vdecls; /* of stree_vdecl_t */
+} stype_block_vr_t;
+
+/** Procedure visit record
+ *
+ * A procedure can be a member function or a property getter or setter. A
+ * procedure visit record is created whenever @c stype (the static typing
+ * pass) enters a procedure.
+ */
+typedef struct run_proc_vr {
+	/** Definition of function or property being invoked */
+	struct stree_proc *proc;
+
+	/** Block activation records */
+	list_t block_vr; /* of run_block_ar_t */
+} stype_proc_vr_t;
+
+/** Static typer state object */
+typedef struct stype {
+	/** Code of the program being typed */
+	struct stree_program *program;
+
+	/**
+	 * CSI context in which we are currently typing. We keep an implicit
+	 * stack of these (in instances of local variable
+	 * @c stype_csi::prev_ctx.)
+	 */
+	struct stree_csi *current_csi;
+
+	/** Procedure VR for the current procedure. */
+	stype_proc_vr_t *proc_vr;
+} stype_t;
+
+#endif
Index: uspace/app/sbi/src/symbol.c
===================================================================
--- uspace/app/sbi/src/symbol.c	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/symbol.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -322,5 +322,5 @@
 
 /** Print fully qualified name of symbol. */
-void symbol_print_fqn(stree_program_t *prog, stree_symbol_t *symbol)
+void symbol_print_fqn(stree_symbol_t *symbol)
 {
 	stree_ident_t *name;
@@ -329,5 +329,5 @@
 	if (symbol->outer_csi != NULL) {
 		outer_sym = csi_to_symbol(symbol->outer_csi);
-		symbol_print_fqn(prog, outer_sym);
+		symbol_print_fqn( outer_sym);
 		printf(".");
 	}
Index: uspace/app/sbi/src/symbol.h
===================================================================
--- uspace/app/sbi/src/symbol.h	(revision 771599490c9c1e7f468c40fc138f10e8ac0282dc)
+++ uspace/app/sbi/src/symbol.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -49,5 +49,5 @@
 stree_symbol_t *prop_to_symbol(stree_prop_t *prop);
 
-void symbol_print_fqn(stree_program_t *prog, stree_symbol_t *symbol);
+void symbol_print_fqn(stree_symbol_t *symbol);
 
 #endif
Index: uspace/app/sbi/src/tdata.c
===================================================================
--- uspace/app/sbi/src/tdata.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/tdata.c	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Run-time data representation. */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "mytypes.h"
+#include "stree.h"
+#include "symbol.h"
+
+#include "tdata.h"
+
+static void tdata_tprimitive_print(tdata_primitive_t *tprimitive);
+static void tdata_tobject_print(tdata_object_t *tobject);
+static void tdata_tarray_print(tdata_array_t *tarray);
+static void tdata_tgeneric_print(tdata_generic_t *tgeneric);
+static void tdata_tfun_print(tdata_fun_t *tfun);
+
+/** Determine if CSI @a a is derived from CSI described by type item @a tb. */
+bool_t tdata_is_csi_derived_from_ti(stree_csi_t *a, tdata_item_t *tb)
+{
+	bool_t res;
+
+	switch (tb->tic) {
+	case tic_tobject:
+		res = stree_is_csi_derived_from_csi(a, tb->u.tobject->csi);
+		break;
+	default:
+		printf("Error: Base type is not a CSI.\n");
+		exit(1);
+	}
+
+	return res;
+}
+
+/** Determine if two type items are equal (i.e. describe the same type). */
+bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b)
+{
+	/*
+	 * Special case: Nil vs. object
+	 *
+	 * XXX Type of @c Nil should probably be @c object to avoid this
+	 * madness.
+	 */
+	if (a->tic == tic_tprimitive && a->u.tprimitive->tpc == tpc_nil) {
+		if (b->tic == tic_tobject)
+			return b_true;
+	} else if (b->tic == tic_tprimitive && b->u.tprimitive->tpc == tpc_nil) {
+		if (a->tic == tic_tobject)
+			return b_true;
+	}
+
+	if (a->tic != b->tic)
+		return b_false;
+
+	switch (a->tic) {
+	case tic_tprimitive:
+		/* Check if both have the same tprimitive class. */
+		return (a->u.tprimitive->tpc == b->u.tprimitive->tpc);
+	case tic_tobject:
+		/* Check if both use the same CSI definition. */
+		return (a->u.tobject->csi == b->u.tobject->csi);
+	case tic_tarray:
+		/* Compare rank and base type. */
+		if (a->u.tarray->rank != b->u.tarray->rank)
+			return b_false;
+
+		return tdata_item_equal(a->u.tarray->base_ti,
+		    b->u.tarray->base_ti);
+	default:
+		printf("Warning: Unimplemented: Compare types '");
+		tdata_item_print(a);
+		printf("' and '");
+		tdata_item_print(b);
+		printf("'.\n");
+		return b_true;
+	}
+}
+
+/** Print type item. */
+void tdata_item_print(tdata_item_t *titem)
+{
+	if (titem == NULL) {
+		printf("none");
+		return;
+	}
+
+	switch (titem->tic) {
+	case tic_tprimitive:
+		tdata_tprimitive_print(titem->u.tprimitive);
+		break;
+	case tic_tobject:
+		tdata_tobject_print(titem->u.tobject);
+		break;
+	case tic_tarray:
+		tdata_tarray_print(titem->u.tarray);
+		break;
+	case tic_tgeneric:
+		tdata_tgeneric_print(titem->u.tgeneric);
+		break;
+	case tic_tfun:
+		tdata_tfun_print(titem->u.tfun);
+		break;
+	}
+}
+
+static void tdata_tprimitive_print(tdata_primitive_t *tprimitive)
+{
+	switch (tprimitive->tpc) {
+	case tpc_int: printf("int"); break;
+	case tpc_nil: printf("nil"); break;
+	case tpc_string: printf("string"); break;
+	}
+}
+
+static void tdata_tobject_print(tdata_object_t *tobject)
+{
+	stree_symbol_t *csi_sym;
+
+	csi_sym = csi_to_symbol(tobject->csi);
+	assert(csi_sym != NULL);
+	symbol_print_fqn(csi_sym);
+}
+
+static void tdata_tarray_print(tdata_array_t *tarray)
+{
+	int i;
+
+	tdata_item_print(tarray->base_ti);
+
+	printf("[");
+	for (i = 0; i < tarray->rank; ++i)
+		printf(",");
+	printf("]");
+}
+
+static void tdata_tgeneric_print(tdata_generic_t *tgeneric)
+{
+	(void) tgeneric;
+	printf("unimplemented(generic)");
+}
+
+static void tdata_tfun_print(tdata_fun_t *tfun)
+{
+	(void) tfun;
+	printf("unimplemented(fun)");
+}
+
+tdata_item_t *tdata_item_new(titem_class_t tic)
+{
+	tdata_item_t *titem;
+
+	titem = calloc(1, sizeof(tdata_item_t));
+	if (titem == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	titem->tic = tic;
+	return titem;
+}
+
+tdata_array_t *tdata_array_new(void)
+{
+	tdata_array_t *tarray;
+
+	tarray = calloc(1, sizeof(tdata_array_t));
+	if (tarray == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tarray;
+}
+
+tdata_object_t *tdata_object_new(void)
+{
+	tdata_object_t *tobject;
+
+	tobject = calloc(1, sizeof(tdata_object_t));
+	if (tobject == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tobject;
+}
+
+tdata_primitive_t *tdata_primitive_new(tprimitive_class_t tpc)
+{
+	tdata_primitive_t *tprimitive;
+
+	tprimitive = calloc(1, sizeof(tdata_primitive_t));
+	if (tprimitive == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	tprimitive->tpc = tpc;
+	return tprimitive;
+}
+
+tdata_fun_t *tdata_fun_new(void)
+{
+	tdata_fun_t *tfun;
+
+	tfun = calloc(1, sizeof(tdata_fun_t));
+	if (tfun == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tfun;
+}
Index: uspace/app/sbi/src/tdata.h
===================================================================
--- uspace/app/sbi/src/tdata.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/tdata.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TDATA_H_
+#define TDATA_H_
+
+#include "mytypes.h"
+
+tdata_item_t *tdata_item_new(titem_class_t tic);
+tdata_array_t *tdata_array_new(void);
+tdata_object_t *tdata_object_new(void);
+tdata_primitive_t *tdata_primitive_new(tprimitive_class_t tpc);
+tdata_fun_t *tdata_fun_new(void);
+
+bool_t tdata_is_csi_derived_from_ti(stree_csi_t *a, tdata_item_t *tb);
+bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b);
+void tdata_item_print(tdata_item_t *titem);
+
+#endif
Index: uspace/app/sbi/src/tdata_t.h
===================================================================
--- uspace/app/sbi/src/tdata_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
+++ uspace/app/sbi/src/tdata_t.h	(revision 39e8406404efea86e341847c0720d5d65bed7959)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Static type system representation. */
+
+#ifndef TDATA_T_H_
+#define TDATA_T_H_
+
+/** Class of primitive type. */
+typedef enum {
+	/** Integer type */
+	tpc_int,
+	/** Special type for nil reference */
+	tpc_nil,
+	/** String type */
+	tpc_string
+} tprimitive_class_t;
+
+/** Primitive type. */
+typedef struct {
+	/** Class of primitive type */
+	tprimitive_class_t tpc;
+} tdata_primitive_t;
+
+/** Object type. */
+typedef struct {
+	/** @c true if expression is a static CSI reference */
+	bool_t static_ref;
+
+	/** CSI definition */
+	struct stree_csi *csi;
+} tdata_object_t;
+
+/** Array type. */
+typedef struct {
+	/** Base type item */
+	struct tdata_item *base_ti;
+
+	/** Rank */
+	int rank;
+
+	/** Extents */
+	list_t extents; /* of stree_expr_t */
+} tdata_array_t;
+
+/** Generic type. */
+typedef struct {
+} tdata_generic_t;
+
+/** Functional type. */
+typedef struct {
+	/**
+	 * Function definition. We'll leave expansion to the call operation.
+	 */
+	struct stree_fun *fun;
+} tdata_fun_t;
+
+typedef enum {
+	tic_tprimitive,
+	tic_tobject,
+	tic_tarray,
+	tic_tgeneric,
+	tic_tfun
+} titem_class_t;
+
+/** Type item, the result of evaluating a type expression. */
+typedef struct tdata_item {
+	titem_class_t tic;
+
+	union {
+		tdata_primitive_t *tprimitive;
+		tdata_object_t *tobject;
+		tdata_array_t *tarray;
+		tdata_generic_t *tgeneric;
+		tdata_fun_t *tfun;
+	} u;
+} tdata_item_t;
+
+#endif
