Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/Makefile	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -38,8 +38,10 @@
 	src/builtin/bi_fun.c \
 	src/builtin/bi_textfile.c \
+	src/builtin/bi_string.c \
 	src/os/helenos.c \
 	src/ancr.c \
 	src/bigint.c \
 	src/builtin.c \
+	src/cspan.c \
 	src/imode.c \
 	src/input.c \
Index: uspace/app/sbi/src/ancr.c
===================================================================
--- uspace/app/sbi/src/ancr.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/ancr.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -81,6 +81,12 @@
 	while (node != NULL) {
 		modm = list_node_data(node, stree_modm_t *);
-		assert(modm->mc == mc_csi); /* XXX */
-		ancr_csi_dfs(prog, modm->u.csi);
+
+		switch (modm->mc) {
+		case mc_csi:
+			ancr_csi_dfs(prog, modm->u.csi);
+			break;
+		case mc_enum:
+			break;
+		}
 
 		node = list_next(&prog->module->members, node);
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/builtin.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -44,4 +44,5 @@
 #include "builtin/bi_fun.h"
 #include "builtin/bi_textfile.h"
+#include "builtin/bi_string.h"
 #include "input.h"
 #include "intmap.h"
@@ -90,4 +91,5 @@
 	bi_fun_declare(bi);
 	bi_textfile_declare(bi);
+	bi_string_declare(bi);
 }
 
@@ -105,4 +107,5 @@
 	bi_fun_bind(bi);
 	bi_textfile_bind(bi);
+	bi_string_bind(bi);
 }
 
Index: uspace/app/sbi/src/builtin/bi_string.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_string.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
+++ uspace/app/sbi/src/builtin/bi_string.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -0,0 +1,181 @@
+/*
+ * 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 String builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../bigint.h"
+#include "../builtin.h"
+#include "../debug.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../rdata.h"
+#include "../run.h"
+#include "../strtab.h"
+
+#include "bi_string.h"
+
+static void bi_string_length(run_t *run);
+static void bi_string_slice(run_t *run);
+
+/** Declare String builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_string_declare(builtin_t *bi)
+{
+	(void) bi;
+}
+
+/** Bind String builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_string_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "String", "get_length", bi_string_length);
+	builtin_fun_bind(bi, "String", "Slice", bi_string_slice);
+}
+
+/** Return length of the string.
+ *
+ * @param run	Runner object
+ */
+static void bi_string_length(run_t *run)
+{
+        rdata_var_t *self_value_var;
+        const char *str;
+        size_t str_l;
+
+	rdata_int_t *rint;
+	rdata_var_t *rvar;
+	rdata_value_t *rval;
+	rdata_item_t *ritem;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract self.Value */
+	self_value_var = builtin_get_self_mbr_var(run, "Value");
+	assert(self_value_var->vc == vc_string);
+	str = self_value_var->u.string_v->value;
+	str_l = os_str_length(str);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Get length of string '%s'.\n", str);
+#endif
+
+	/* Construct return value. */
+	rint = rdata_int_new();
+	bigint_init(&rint->value, (int) str_l);
+
+	rvar = rdata_var_new(vc_int);
+	rvar->u.int_v = rint;
+	rval = rdata_value_new();
+	rval->var = rvar;
+
+	ritem = rdata_item_new(ic_value);
+	ritem->u.value = rval;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = ritem;
+}
+
+/** Return slice (substring) of the string.
+ *
+ * @param run	Runner object
+ */
+static void bi_string_slice(run_t *run)
+{
+        rdata_var_t *self_value_var;
+        const char *str;
+        size_t str_l;
+
+	rdata_var_t *start_var;
+	int start;
+
+	rdata_var_t *length_var;
+	int length;
+
+	int rc;
+
+	rdata_string_t *rstring;
+	rdata_var_t *rvar;
+	rdata_value_t *rval;
+	rdata_item_t *ritem;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract self.Value */
+	self_value_var = builtin_get_self_mbr_var(run, "Value");
+	assert(self_value_var->vc == vc_string);
+	str = self_value_var->u.string_v->value;
+	str_l = os_str_length(str);
+
+	/* Get argument @a start. */
+	start_var = run_local_vars_lookup(run, strtab_get_sid("start"));
+	assert(start_var);
+	assert(start_var->vc == vc_int);
+
+	rc = bigint_get_value_int(&start_var->u.int_v->value, &start);
+	if (rc != EOK || start < 0 || (size_t) start > str_l) {
+		printf("Error: Parameter 'start' to Slice() out of range.\n");
+		exit(1);
+	}
+
+	/* Get argument @a length. */
+	length_var = run_local_vars_lookup(run, strtab_get_sid("length"));
+	assert(length_var);
+	assert(length_var->vc == vc_int);
+
+	rc = bigint_get_value_int(&length_var->u.int_v->value, &length);
+	if (rc != EOK || length < 0 || (size_t) (start + length) > str_l) {
+		printf("Error: Parameter 'length' to Slice() out of range.\n");
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Construct Slice(%d, %d) from string '%s'.\n",
+	    start, length, str);
+#endif
+	/* Construct return value. */
+	rstring = rdata_string_new();
+	rstring->value = os_str_aslice(str, start, length);
+
+	rvar = rdata_var_new(vc_string);
+	rvar->u.string_v = rstring;
+	rval = rdata_value_new();
+	rval->var = rvar;
+
+	ritem = rdata_item_new(ic_value);
+	ritem->u.value = rval;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = ritem;
+}
Index: uspace/app/sbi/src/builtin/bi_string.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_string.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
+++ uspace/app/sbi/src/builtin/bi_string.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -0,0 +1,37 @@
+/*
+ * 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 BI_STRING_H_
+#define BI_STRING_H_
+
+#include "../mytypes.h"
+
+void bi_string_declare(builtin_t *bi);
+void bi_string_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/builtin/bi_textfile.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/builtin/bi_textfile.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -71,5 +71,5 @@
 			"fun WriteLine(line : string), builtin;\n"
 			"\n"
-			"prop EOF : int is\n"
+			"prop EOF : bool is\n"
 				"get is\n"
 					"return is_eof();\n"
@@ -77,5 +77,5 @@
 			"end\n"
 			"\n"
-			"fun is_eof() : int, builtin;\n"
+			"fun is_eof() : bool, builtin;\n"
 		"end\n");
 
@@ -342,6 +342,6 @@
         rdata_var_t *self_f_var;
 
-	int eof_flag;
-	rdata_int_t *eof_int;
+	bool_t eof_flag;
+	rdata_bool_t *eof_bool;
 	rdata_var_t *eof_var;
 	rdata_value_t *eof_val;
@@ -362,15 +362,15 @@
 	/* Get status of EOF flag. */
 
-	eof_flag = feof(file) ? 1 : 0;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Read EOF flag '%d'.\n", eof_flag);
+	eof_flag = feof(file) ? b_true : b_false;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read EOF flag '%s'.\n", eof_flag ? "true" : "false");
 #endif
 	/* Construct return value. */
-	eof_int = rdata_int_new();
-	bigint_init(&eof_int->value, eof_flag);
-
-	eof_var = rdata_var_new(vc_int);
-	eof_var->u.int_v = eof_int;
+	eof_bool = rdata_bool_new();
+	eof_bool->value = eof_flag;
+
+	eof_var = rdata_var_new(vc_bool);
+	eof_var->u.bool_v = eof_bool;
 	eof_val = rdata_value_new();
 	eof_val->var = eof_var;
Index: uspace/app/sbi/src/cspan.c
===================================================================
--- uspace/app/sbi/src/cspan.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
+++ uspace/app/sbi/src/cspan.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -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 Coordinate span
+ *
+ * Captures the origin (input object, starting and ending line number and
+ * columnt number) of a code fragment.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mytypes.h"
+
+#include "cspan.h"
+
+/** Allocate new coordinate span.
+ *
+ * @param	input	Input object.
+ * @param	line	Starting line number.
+ * @param	col0	Starting column number.
+ * @param	line	Ending number (inclusive).
+ * @param	col1	Ending column number (inclusive).
+ *
+ * @return	New coordinate span.
+ */
+cspan_t *cspan_new(input_t *input, int line0, int col0, int line1, int col1)
+{
+	cspan_t *cspan;
+
+	cspan = calloc(1, sizeof(cspan_t));
+	if (cspan == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	cspan->input = input;
+	cspan->line0 = line0;
+	cspan->col0 = col0;
+	cspan->line1 = line1;
+	cspan->col1 = col1;
+
+	return cspan;
+}
+
+/** Create a merged coordinate span.
+ *
+ * Creates the smalles cspan covering cpans @a a and @a b. Both spans
+ * must be from the same input object and @a a must start earlier
+ * than @a b terminates.
+ *
+ * @param	a	First coordinate span
+ * @param	b	Second coordinate span
+ * @return	New coordinate span.
+ */
+cspan_t *cspan_merge(cspan_t *a, cspan_t *b)
+{
+	assert(a != NULL);
+	assert(b != NULL);
+	assert(a->input == b->input);
+
+	return cspan_new(a->input, a->line0, a->col0, b->line1, b->col1);
+}
+
+/** Print coordinate span.
+ *
+ * @param cspan		Coordinate span
+ */
+void cspan_print(cspan_t *cspan)
+{
+	printf("%s:", cspan->input->name);
+
+	if (cspan->line0 != cspan->line1) {
+		printf("%d:%d-%d:%d", cspan->line0, cspan->col0, cspan->line1,
+		    cspan->col1);
+	} else {
+		printf("%d:%d-%d", cspan->line0, cspan->col0, cspan->col1);
+	}
+}
Index: uspace/app/sbi/src/cspan.h
===================================================================
--- uspace/app/sbi/src/cspan.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
+++ uspace/app/sbi/src/cspan.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -0,0 +1,38 @@
+/*
+ * 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 CSPAN_H_
+#define CSPAN_H_
+
+#include "mytypes.h"
+
+cspan_t *cspan_new(input_t *input, int line0, int col0, int line1, int col1);
+cspan_t *cspan_merge(cspan_t *a, cspan_t *b);
+void cspan_print(cspan_t *cspan);
+
+#endif
Index: uspace/app/sbi/src/cspan_t.h
===================================================================
--- uspace/app/sbi/src/cspan_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
+++ uspace/app/sbi/src/cspan_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -0,0 +1,48 @@
+/*
+ * 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 CSPAN_T_H_
+#define CSPAN_T_H_
+
+/** Coordinate span
+ *
+ * A coordinate span records the coordinates of a source code fragment.
+ * It can span multiple lines, but not multiple input objects.
+ */
+typedef struct cspan {
+	/** Input object where the span comes from */
+	struct input *input;
+
+	/* Starting line and column */
+	int line0, col0;
+
+	/* Ending line and column, inclusive. */
+	int line1, col1;
+} cspan_t;
+
+#endif
Index: uspace/app/sbi/src/imode.c
===================================================================
--- uspace/app/sbi/src/imode.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/imode.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -116,4 +116,5 @@
 	fun->name = stree_ident_new();
 	fun->name->sid = strtab_get_sid("$imode");
+	fun->sig = stree_fun_sig_new();
 
 	stype.proc_vr->proc = proc;
Index: uspace/app/sbi/src/input.c
===================================================================
--- uspace/app/sbi/src/input.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/input.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -118,4 +118,5 @@
 	}
 
+	input->name = os_str_dup(fname);
 	input->str = NULL;
 	input->line_no = 0;
@@ -136,4 +137,5 @@
 	}
 
+	input->name = "<user-input>";
 	input->str = NULL;
 	input->line_no = 0;
@@ -154,4 +156,5 @@
 	}
 
+	input->name = "<builtin>";
 	input->str = str;
 	input->line_no = 0;
@@ -226,5 +229,5 @@
 /** Get number of the last provided line of input.
  *
- * @param input		Input module.
+ * @param input		Input object.
  * @return		Line number of the last provided input line (counting
  *			from 1 up).
Index: uspace/app/sbi/src/input_t.h
===================================================================
--- uspace/app/sbi/src/input_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/input_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -34,4 +34,7 @@
 /** Input state object */
 typedef struct input {
+	/** Input name (for error output) */
+	const char *name;
+
 	/** Input file if reading from file. */
 	FILE *fin;
Index: uspace/app/sbi/src/lex.c
===================================================================
--- uspace/app/sbi/src/lex.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/lex.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -35,4 +35,5 @@
 #include <stdlib.h>
 #include "bigint.h"
+#include "cspan.h"
 #include "mytypes.h"
 #include "input.h"
@@ -74,14 +75,17 @@
 /** Keyword names. Used both for printing and recognition. */
 static struct lc_name keywords[] = {
+	{ lc_and,	"and" },
 	{ lc_as,	"as" },
 	{ lc_bool,	"bool" },
+	{ lc_break,	"break" },
+	{ lc_builtin,	"builtin" },
 	{ lc_char,	"char" },
-	{ lc_builtin,	"builtin" },
 	{ lc_class,	"class" },
-	{ lc_constructor,	"constructor" },
 	{ lc_deleg,	"deleg" },
 	{ lc_do,	"do" },
+	{ lc_elif,	"elif" },
 	{ lc_else,	"else" },
 	{ lc_end,	"end" },
+	{ lc_enum,	"enum" },
 	{ lc_except,	"except" },
 	{ lc_false,	"false" },
@@ -96,5 +100,7 @@
 	{ lc_is,	"is" },
 	{ lc_new,	"new" },
+	{ lc_not,	"not" },
 	{ lc_nil,	"nil" },
+	{ lc_or,	"or" },
 	{ lc_override,	"override" },
 	{ lc_packed,	"packed" },
@@ -233,5 +239,5 @@
 void lem_print_coords(lem_t *lem)
 {
-	printf("%d:%d", lem->line_no, lem->col_0);
+	cspan_print(lem->cspan);
 }
 
@@ -255,4 +261,5 @@
 	lex->ibp = lex->inbuf;
 	lex->col_adj = 0;
+	lex->prev_valid = b_false;
 	lex->current_valid = b_true;
 }
@@ -279,5 +286,5 @@
  * @param lex		Lexer object.
  * @return		Pointer to current lem. Owned by @a lex and only valid
- *			until next call to lex_next().
+ *			until next call to lex_xxx().
  */
 lem_t *lex_get_current(lex_t *lex)
@@ -287,4 +294,34 @@
 }
 
+/** Get previous lem if valid.
+ *
+ * The returned pointer is invalidated by next call to lex_next()
+ *
+ * @param lex		Lexer object.
+ * @return		Pointer to previous lem. Owned by @a lex and only valid
+ *			until next call to lex_xxx().
+ */
+lem_t *lex_peek_prev(lex_t *lex)
+{
+	if (lex->current_valid == b_false) {
+		/*
+		 * This means the head is advanced but next lem was not read.
+		 * Thus the previous lem is still in @a current.
+		 */
+		return &lex->current;
+	}
+
+	if (lex->prev_valid != b_true) {
+		/* Looks like we are still at the first lem. */
+		return NULL;
+	}
+
+	/*
+	 * Current lem has been read in. Thus the previous lem was moved to
+	 * @a previous.
+	 */
+	return &lex->prev;
+}
+
 /** Read in the current lexical element (unless already read in).
  *
@@ -297,4 +334,8 @@
 	if (lex->current_valid == b_true)
 		return;
+
+	/* Copy previous lem */
+	lex->prev = lex->current;
+	lex->prev_valid = b_true;
 
 	do {
@@ -318,5 +359,6 @@
 static bool_t lex_read_try(lex_t *lex)
 {
-	char *bp;
+	char *bp, *lsp;
+	int line0, col0;
 
 	lex_skip_ws(lex);
@@ -328,7 +370,10 @@
 	 * separately using col_adj.
 	 */
-	lex->current.line_no = input_get_line_no(lex->input);
-	lex->current.col_0 = 1 + lex->col_adj + (lex->ibp - lex->inbuf);
-
+	line0 = input_get_line_no(lex->input);
+	col0 = 1 + lex->col_adj + (lex->ibp - lex->inbuf);
+
+	lex->current.cspan = cspan_new(lex->input, line0, col0, line0, col0);
+
+	lsp = lex->ibp;
 	bp = lex->ibp;
 
@@ -336,29 +381,34 @@
 		/* End of input */
 		lex->current.lclass = lc_eof;
-		return b_true;
+		goto finish;
 	}
 
 	if (is_wstart(bp[0])) {
 		lex_word(lex);
-		return b_true;
+		goto finish;
 	}
 
 	if (bp[0] == '\'') {
 		lex_char(lex);
-		return b_true;
+		goto finish;
 	}
 
 	if (is_digit(bp[0])) {
 		lex_number(lex);
-		return b_true;
+		goto finish;
 	}
 
 	if (bp[0] == '"') {
 		lex_string(lex);
-		return b_true;
+		goto finish;
 	}
 
 	if (bp[0] == '-' && bp[1] == '-') {
 		lex_skip_comment(lex);
+
+		/* Compute ending column number */
+		lex->current.cspan->col1 = col0 + (lex->ibp - lsp) - 1;
+
+		/* Try again */
 		return b_false;
 	}
@@ -417,4 +467,8 @@
 
 	lex->ibp = bp;
+
+finish:
+	/* Compute ending column number */
+	lex->current.cspan->col1 = col0 + (lex->ibp - lsp) - 1;
 	return b_true;
 
Index: uspace/app/sbi/src/lex.h
===================================================================
--- uspace/app/sbi/src/lex.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/lex.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -39,4 +39,5 @@
 void lex_next(lex_t *lex);
 lem_t *lex_get_current(lex_t *lex);
+lem_t *lex_peek_prev(lex_t *lex);
 
 #endif
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/lex_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -43,14 +43,17 @@
 
 	/* Keywords */
+	lc_and,
 	lc_as,
+	lc_break,
 	lc_bool,
 	lc_builtin,
 	lc_char,
 	lc_class,
-	lc_constructor,
 	lc_deleg,
 	lc_do,
+	lc_elif,
 	lc_else,
 	lc_end,
+	lc_enum,
 	lc_except,
 	lc_false,
@@ -66,4 +69,6 @@
 	lc_is,
 	lc_nil,
+	lc_not,
+	lc_or,
 	lc_override,
 	lc_packed,
@@ -148,5 +153,5 @@
 
 	/** Coordinates of this lexical element */
-	int line_no, col_0;
+	struct cspan *cspan;
 } lem_t;
 
@@ -168,5 +173,11 @@
 	int col_adj;
 
-	/** @c b_true if we have the next lem in @c current */
+	/** @c b_true if we have the previous lem in @c prev */
+	bool_t prev_valid;
+
+	/** Previous lem (only valid if @c current_valid is true) */
+	lem_t prev;
+
+	/** @c b_true if we have the current lem in @c current */
 	bool_t current_valid;
 
Index: uspace/app/sbi/src/mytypes.h
===================================================================
--- uspace/app/sbi/src/mytypes.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/mytypes.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -49,4 +49,5 @@
 #include "bigint_t.h"
 #include "builtin_t.h"
+#include "cspan_t.h"
 #include "input_t.h"
 #include "intmap_t.h"
Index: uspace/app/sbi/src/os/helenos.c
===================================================================
--- uspace/app/sbi/src/os/helenos.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/os/helenos.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -29,4 +29,5 @@
 /** @file HelenOS-specific code. */
 
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
@@ -75,4 +76,40 @@
 }
 
+/** Return slice (substring) of a string.
+ *
+ * Copies the specified range of characters from @a str and returns it
+ * as a newly allocated string. @a start + @a length must be less than
+ * or equal to the length of @a str.
+ *
+ * @param str		String
+ * @param start		Index of first character (starting from zero).
+ * @param length	Number of characters to copy.
+ *
+ * @return		Newly allocated string holding the slice.
+ */
+char *os_str_aslice(const char *str, size_t start, size_t length)
+{
+	char *slice;
+	size_t offset;
+	size_t i;
+	size_t size;
+	wchar_t c;
+
+	assert(start + length <= str_length(str));
+
+	offset = 0;
+	for (i = 0; i < start; ++i) {
+		c = str_decode(str, &offset, STR_NO_LIMIT);
+		assert(c != '\0');
+		assert(c != U_SPECIAL);
+		(void) c;
+	}
+
+	size = str_lsize(str, length);
+	slice = str_ndup(str + offset, size);
+
+	return slice;
+}
+
 /** Compare two strings.
  *
Index: uspace/app/sbi/src/os/os.h
===================================================================
--- uspace/app/sbi/src/os/os.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/os/os.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -31,4 +31,5 @@
 
 char *os_str_acat(const char *a, const char *b);
+char *os_str_aslice(const char *str, size_t start, size_t length);
 int os_str_cmp(const char *a, const char *b);
 char *os_str_dup(const char *str);
Index: uspace/app/sbi/src/os/posix.c
===================================================================
--- uspace/app/sbi/src/os/posix.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/os/posix.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -29,4 +29,5 @@
 /** @file POSIX-specific code. */
 
+#include <assert.h>
 #include <libgen.h>
 #include <stdio.h>
@@ -78,4 +79,33 @@
 }
 
+/** Return slice (substring) of a string.
+ *
+ * Copies the specified range of characters from @a str and returns it
+ * as a newly allocated string. @a start + @a length must be less than
+ * or equal to the length of @a str.
+ *
+ * @param str		String
+ * @param start		Index of first character (starting from zero).
+ * @param length	Number of characters to copy.
+ *
+ * @return		Newly allocated string holding the slice.
+ */
+char *os_str_aslice(const char *str, size_t start, size_t length)
+{
+	char *slice;
+
+	assert(start + length <= strlen(str));
+	slice = malloc(length + 1);
+	if (slice == NULL) {
+		printf("Memory allocation error.\n");
+		exit(1);
+	}
+
+	strncpy(slice, str + start, length);
+	slice[length] = '\0';
+
+	return slice;
+}
+
 /** Compare two strings.
  *
Index: uspace/app/sbi/src/p_expr.c
===================================================================
--- uspace/app/sbi/src/p_expr.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/p_expr.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -32,4 +32,5 @@
 #include <stdlib.h>
 #include "bigint.h"
+#include "cspan.h"
 #include "debug.h"
 #include "lex.h"
@@ -43,4 +44,6 @@
 
 static stree_expr_t *parse_assign(parse_t *parse);
+static stree_expr_t *parse_disjunctive(parse_t *parse);
+static stree_expr_t *parse_conjunctive(parse_t *parse);
 static stree_expr_t *parse_comparative(parse_t *parse);
 static stree_expr_t *parse_additive(parse_t *parse);
@@ -95,5 +98,5 @@
 	stree_assign_t *assign;
 
-	a = parse_comparative(parse);
+	a = parse_disjunctive(parse);
 
 	switch (lcur_lc(parse)) {
@@ -109,5 +112,5 @@
 
 	lskip(parse);
-	b = parse_comparative(parse);
+	b = parse_disjunctive(parse);
 
 	assign->dest = a;
@@ -116,5 +119,81 @@
 	tmp = stree_expr_new(ec_assign);
 	tmp->u.assign = assign;
+	tmp->cspan = cspan_merge(a->cspan, b->cspan);
+
+	assign->expr = tmp;
+
 	return tmp;
+}
+
+/** Parse disjunctive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_disjunctive(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	cspan_t *cs;
+
+	a = parse_conjunctive(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_or) {
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_conjunctive(parse);
+
+		binop = stree_binop_new(bo_or);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
+}
+
+/** Parse conjunctive expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_expr_t *parse_conjunctive(parse_t *parse)
+{
+	stree_expr_t *a, *b, *tmp;
+	stree_binop_t *binop;
+	cspan_t *cs;
+
+	a = parse_comparative(parse);
+	cs = a->cspan;
+
+	while (lcur_lc(parse) == lc_and) {
+		if (parse_is_error(parse))
+			break;
+
+		lskip(parse);
+		b = parse_comparative(parse);
+
+		binop = stree_binop_new(bo_and);
+		binop->arg1 = a;
+		binop->arg2 = b;
+
+		tmp = stree_expr_new(ec_binop);
+		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
+		a = tmp;
+		cs = tmp->cspan;
+	}
+
+	return a;
 }
 
@@ -128,6 +207,8 @@
 	stree_binop_t *binop;
 	binop_class_t bc;
+	cspan_t *cs;
 
 	a = parse_additive(parse);
+	cs = a->cspan;
 
 	while (lcur_lc(parse) == lc_equal || lcur_lc(parse) == lc_notequal ||
@@ -157,5 +238,9 @@
 		tmp = stree_expr_new(ec_binop);
 		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
 		a = tmp;
+		cs = tmp->cspan;
 	}
 
@@ -172,6 +257,9 @@
 	stree_binop_t *binop;
 	binop_class_t bc;
+	cspan_t *cs;
 
 	a = parse_multip(parse);
+	cs = a->cspan;
+
 	while (lcur_lc(parse) == lc_plus || lcur_lc(parse) == lc_minus) {
 		if (parse_is_error(parse))
@@ -193,5 +281,9 @@
 		tmp = stree_expr_new(ec_binop);
 		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
 		a = tmp;
+		cs = tmp->cspan;
 	}
 
@@ -208,6 +300,9 @@
 	stree_binop_t *binop;
 	binop_class_t bc;
+	cspan_t *cs;
 
 	a = parse_prefix(parse);
+	cs = a->cspan;
+
 	while (lcur_lc(parse) == lc_mult) {
 		if (parse_is_error(parse))
@@ -228,5 +323,9 @@
 		tmp = stree_expr_new(ec_binop);
 		tmp->u.binop = binop;
+		tmp->cspan = cspan_merge(cs, b->cspan);
+		binop->expr = tmp;
+
 		a = tmp;
+		cs = tmp->cspan;
 	}
 
@@ -244,8 +343,10 @@
 	stree_unop_t *unop;
 	unop_class_t uc;
+	cspan_t *cs0;
 
 	switch (lcur_lc(parse)) {
 	case lc_plus:
 	case lc_minus:
+	case lc_not:
 		if (parse_is_error(parse))
 			return parse_recovery_expr(parse);
@@ -254,7 +355,9 @@
 		case lc_plus: uc = uo_plus; break;
 		case lc_minus: uc = uo_minus; break;
+		case lc_not: uc = uo_not; break;
 		default: assert(b_false);
 		}
 
+		cs0 = lcur_span(parse);
 		lskip(parse);
 		a = parse_postfix(parse);
@@ -265,4 +368,6 @@
 		tmp = stree_expr_new(ec_unop);
 		tmp->u.unop = unop;
+		tmp->cspan = cspan_merge(cs0, a->cspan);
+		unop->expr = tmp;
 		a = tmp;
 		break;
@@ -287,13 +392,13 @@
 	stree_new_t *new_op;
 	stree_expr_t *expr;
-
+	stree_expr_t *arg;
+	cspan_t *cs0, *cs1;
+
+	cs0 = lcur_span(parse);
 	lmatch(parse, lc_new);
 	texpr = parse_texpr(parse);
 
-	/* Parenthesis should be present except for arrays. */
-	if (texpr->tc != tc_tindex) {
-		lmatch(parse, lc_lparen);
-		lmatch(parse, lc_rparen);
-	}
+	/* XXX Take span from texpr */
+	cs1 = lprev_span(parse);
 
 	new_op = stree_new_new();
@@ -302,4 +407,30 @@
 	expr->u.new_op = new_op;
 
+	list_init(&new_op->ctor_args);
+
+	/* Parenthesized arguments should be present except for arrays. */
+	if (texpr->tc != tc_tindex) {
+		lmatch(parse, lc_lparen);
+
+		/* Parse constructor arguments */
+
+		if (lcur_lc(parse) != lc_rparen) {
+			while (!parse_is_error(parse)) {
+				arg = parse_expr(parse);
+				list_append(&new_op->ctor_args, arg);
+
+				if (lcur_lc(parse) == lc_rparen)
+					break;
+				lmatch(parse, lc_comma);
+			}
+		}
+
+		lmatch(parse, lc_rparen);
+		cs1 = cspan_merge(cs0, lprev_span(parse));
+	}
+
+	expr->cspan = cspan_merge(cs0, cs1);
+	new_op->expr = expr;
+
 	return expr;
 }
@@ -354,7 +485,11 @@
 	stree_expr_t *expr;
 	stree_access_t *access;
+	cspan_t *cs1;
 
 	lmatch(parse, lc_period);
 	ident = parse_ident(parse);
+
+	/* XXX Take span from ident */
+	cs1 = lprev_span(parse);
 
 	access = stree_access_new();
@@ -364,4 +499,7 @@
 	expr = stree_expr_new(ec_access);
 	expr->u.access = access;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+
+	access->expr = expr;
 
 	return expr;
@@ -377,4 +515,5 @@
 	stree_call_t *call;
 	stree_expr_t *arg;
+	cspan_t *cs1;
 
 	lmatch(parse, lc_lparen);
@@ -398,7 +537,10 @@
 
 	lmatch(parse, lc_rparen);
+	cs1 = lprev_span(parse);
 
 	expr = stree_expr_new(ec_call);
 	expr->u.call = call;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+	call->expr = expr;
 
 	return expr;
@@ -414,4 +556,5 @@
 	stree_index_t *index;
 	stree_expr_t *arg;
+	cspan_t *cs1;
 
 	lmatch(parse, lc_lsbr);
@@ -435,7 +578,10 @@
 
 	lmatch(parse, lc_rsbr);
+	cs1 = lprev_span(parse);
 
 	expr = stree_expr_new(ec_index);
 	expr->u.index = index;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+	index->expr = expr;
 
 	return expr;
@@ -451,13 +597,21 @@
 	stree_texpr_t *texpr;
 	stree_as_t *as_op;
+	cspan_t *cs1;
 
 	lmatch(parse, lc_as);
 	texpr = parse_texpr(parse);
+
+	/* XXX Take span from texpr */
+	cs1 = lprev_span(parse);
 
 	as_op = stree_as_new();
 	as_op->arg = a;
 	as_op->dtype = texpr;
+
 	expr = stree_expr_new(ec_as);
 	expr->u.as_op = as_op;
+	expr->cspan = cspan_merge(a->cspan, cs1);
+
+	as_op->expr = expr;
 
 	return expr;
@@ -471,9 +625,14 @@
 {
 	stree_expr_t *expr;
+	cspan_t *cs0, *cs1;
 
 	if (lcur_lc(parse) == lc_lparen) {
+		cs0 = lcur_span(parse);
 		lskip(parse);
 		expr = parse_expr(parse);
 		lmatch(parse, lc_rparen);
+		cs1 = lprev_span(parse);
+
+		expr->cspan = cspan_merge(cs0, cs1);
 	} else {
 		expr = parse_primitive(parse);
@@ -482,5 +641,4 @@
 	return expr;
 }
-
 
 /** Parse primitive expression.
@@ -536,4 +694,6 @@
 	expr = stree_expr_new(ec_nameref);
 	expr->u.nameref = nameref;
+	expr->cspan = lprev_span(parse);
+	nameref->expr = expr;
 
 	return expr;
@@ -563,4 +723,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
 
 	return expr;
@@ -586,4 +748,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
 
 	return expr;
@@ -609,4 +773,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
 
 	return expr;
@@ -628,4 +794,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
 
 	return expr;
@@ -650,4 +818,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
+	expr->cspan = lprev_span(parse);
+	literal->expr = expr;
 
 	return expr;
@@ -669,4 +839,6 @@
 	expr = stree_expr_new(ec_self_ref);
 	expr->u.self_ref = self_ref;
+	expr->cspan = lprev_span(parse);
+	self_ref->expr = expr;
 
 	return expr;
@@ -688,5 +860,6 @@
 	expr = stree_expr_new(ec_literal);
 	expr->u.literal = literal;
-
-	return expr;
-}
+	literal->expr = expr;
+
+	return expr;
+}
Index: uspace/app/sbi/src/p_type.c
===================================================================
--- uspace/app/sbi/src/p_type.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/p_type.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -31,4 +31,5 @@
 #include <assert.h>
 #include <stdlib.h>
+#include "cspan.h"
 #include "debug.h"
 #include "lex.h"
@@ -45,7 +46,8 @@
 static stree_texpr_t *parse_pf_taccess(parse_t *parse, stree_texpr_t *a);
 static stree_texpr_t *parse_pf_tindex(parse_t *parse, stree_texpr_t *a);
+static stree_texpr_t *parse_tparen(parse_t *parse);
 static stree_texpr_t *parse_tprimitive(parse_t *parse);
-static stree_tliteral_t *parse_tliteral(parse_t *parse);
-static stree_tnameref_t *parse_tnameref(parse_t *parse);
+static stree_texpr_t *parse_tliteral(parse_t *parse);
+static stree_texpr_t *parse_tnameref(parse_t *parse);
 
 static stree_texpr_t *parse_recovery_texpr(parse_t *parse);
@@ -91,4 +93,6 @@
 	list_init(&tapply->targs);
 
+	targ = NULL;
+
 	while (lcur_lc(parse) == lc_slash) {
 
@@ -104,4 +108,11 @@
 	aexpr = stree_texpr_new(tc_tapply);
 	aexpr->u.tapply = tapply;
+	tapply->texpr = aexpr;
+
+	if (targ != NULL)
+		aexpr->cspan = cspan_merge(gtype->cspan, targ->cspan);
+	else
+		aexpr->cspan = gtype->cspan;
+
 	return aexpr;
 }
@@ -116,5 +127,5 @@
 	stree_texpr_t *tmp;
 
-	a = parse_tprimitive(parse);
+	a = parse_tparen(parse);
 
 	while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lsbr) {
@@ -162,4 +173,6 @@
 	texpr = stree_texpr_new(tc_taccess);
 	texpr->u.taccess = taccess;
+	taccess->texpr = texpr;
+	texpr->cspan = cspan_merge(a->cspan, ident->cspan);
 
 	return texpr;
@@ -176,4 +189,5 @@
 	stree_tindex_t *tindex;
 	stree_expr_t *expr;
+	cspan_t *cs1;
 
 	tindex = stree_tindex_new();
@@ -209,10 +223,37 @@
 
 	lmatch(parse, lc_rsbr);
+	cs1 = lprev_span(parse);
 
 	texpr = stree_texpr_new(tc_tindex);
 	texpr->u.tindex = tindex;
-
-	return texpr;
-}
+	tindex->texpr = texpr;
+	texpr->cspan = cspan_merge(a->cspan, cs1);
+
+	return texpr;
+}
+
+/** Parse possibly partenthesized type expression.
+ *
+ * @param parse		Parser object.
+ */
+static stree_texpr_t *parse_tparen(parse_t *parse)
+{
+	stree_texpr_t *texpr;
+	cspan_t *cs0, *cs1;
+
+	if (lcur_lc(parse) == lc_lparen) {
+		cs0 = lcur_span(parse);
+		lskip(parse);
+		texpr = parse_texpr(parse);
+		lmatch(parse, lc_rparen);
+		cs1 = lprev_span(parse);
+		texpr->cspan = cspan_merge(cs0, cs1);
+	} else {
+		texpr = parse_tprimitive(parse);
+	}
+
+	return texpr;
+}
+
 
 /** Parse primitive type expression.
@@ -226,6 +267,5 @@
 	switch (lcur_lc(parse)) {
 	case lc_ident:
-		texpr = stree_texpr_new(tc_tnameref);
-		texpr->u.tnameref = parse_tnameref(parse);
+		texpr = parse_tnameref(parse);
 		break;
 	case lc_bool:
@@ -234,6 +274,5 @@
 	case lc_string:
 	case lc_resource:
-		texpr = stree_texpr_new(tc_tliteral);
-		texpr->u.tliteral = parse_tliteral(parse);
+		texpr = parse_tliteral(parse);
 		break;
 	default:
@@ -250,8 +289,9 @@
  * @param parse		Parser object.
  */
-static stree_tliteral_t *parse_tliteral(parse_t *parse)
+static stree_texpr_t *parse_tliteral(parse_t *parse)
 {
 	stree_tliteral_t *tliteral;
 	tliteral_class_t tlc;
+	stree_texpr_t *texpr;
 
 	switch (lcur_lc(parse)) {
@@ -278,5 +318,10 @@
 
 	tliteral = stree_tliteral_new(tlc);
-	return tliteral;
+	texpr = stree_texpr_new(tc_tliteral);
+	texpr->u.tliteral = tliteral;
+	tliteral->texpr = texpr;
+	texpr->cspan = lprev_span(parse);
+
+	return texpr;
 }
 
@@ -285,12 +330,18 @@
  * @param parse		Parser object.
  */
-static stree_tnameref_t *parse_tnameref(parse_t *parse)
+static stree_texpr_t *parse_tnameref(parse_t *parse)
 {
 	stree_tnameref_t *tnameref;
+	stree_texpr_t *texpr;
 
 	tnameref = stree_tnameref_new();
 	tnameref->name = parse_ident(parse);
 
-	return tnameref;
+	texpr = stree_texpr_new(tc_tnameref);
+	texpr->u.tnameref = tnameref;
+	tnameref->texpr = texpr;
+	texpr->cspan = tnameref->name->cspan;
+
+	return texpr;
 }
 
@@ -310,5 +361,6 @@
 	texpr = stree_texpr_new(tc_tliteral);
 	texpr->u.tliteral = tliteral;
-
-	return texpr;
-}
+	tliteral->texpr = texpr;
+
+	return texpr;
+}
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/parse.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -48,9 +48,14 @@
 
 /*
- * Module members
+ * Module and CSI members
  */
 static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
     stree_csi_t *outer_csi);
 static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi);
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum);
 
 static stree_deleg_t *parse_deleg(parse_t *parse, stree_csi_t *outer_csi);
@@ -76,4 +81,5 @@
 static stree_for_t *parse_for(parse_t *parse);
 static stree_raise_t *parse_raise(parse_t *parse);
+static stree_break_t *parse_break(parse_t *parse);
 static stree_return_t *parse_return(parse_t *parse);
 static stree_wef_t *parse_wef(parse_t *parse);
@@ -123,4 +129,5 @@
 {
 	stree_csi_t *csi;
+	stree_enum_t *enum_d;
 	stree_modm_t *modm;
 
@@ -136,4 +143,11 @@
 			list_append(&parse->cur_mod->members, modm);
 			break;
+		case lc_enum:
+			enum_d = parse_enum(parse, NULL);
+			modm = stree_modm_new(mc_enum);
+			modm->u.enum_d = enum_d;
+
+			list_append(&parse->cur_mod->members, modm);
+			break;
 		default:
 			lunexpected_error(parse);
@@ -223,5 +237,5 @@
  *
  * @param parse		Parser object.
- * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @param outer_csi	CSI containing this declaration.
  * @return		New syntax tree node. In case of parse error,
  *			@c NULL may (but need not) be returned.
@@ -232,5 +246,7 @@
 
 	stree_csi_t *csi;
+	stree_ctor_t *ctor;
 	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
 	stree_fun_t *fun;
 	stree_var_t *var;
@@ -245,4 +261,9 @@
 		csimbr->u.csi = csi;
 		break;
+	case lc_new:
+		ctor = parse_ctor(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_ctor);
+		csimbr->u.ctor = ctor;
+		break;
 	case lc_deleg:
 		deleg = parse_deleg(parse, outer_csi);
@@ -250,4 +271,9 @@
 		csimbr->u.deleg = deleg;
 		break;
+	case lc_enum:
+		enum_d = parse_enum(parse, outer_csi);
+		csimbr = stree_csimbr_new(csimbr_enum);
+		csimbr->u.enum_d = enum_d;
+		break;
 	case lc_fun:
 		fun = parse_fun(parse, outer_csi);
@@ -273,4 +299,142 @@
 
 	return csimbr;
+}
+
+/** Parse constructor.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_ctor_t *parse_ctor(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_ctor_t *ctor;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
+
+	ctor = stree_ctor_new();
+	symbol = stree_symbol_new(sc_ctor);
+
+	symbol->u.ctor = ctor;
+	symbol->outer_csi = outer_csi;
+	ctor->symbol = symbol;
+
+	lmatch(parse, lc_new);
+
+	/* Fake identifier. */
+	ctor->name = stree_ident_new();
+	ctor->name->sid = strtab_get_sid(CTOR_IDENT);
+	ctor->name->cspan = lprev_span(parse);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parsing constructor of CSI '");
+	symbol_print_fqn(csi_to_symbol(outer_csi));
+	printf("'.\n");
+#endif
+	ctor->sig = parse_fun_sig(parse);
+	if (ctor->sig->rtype != NULL) {
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has a return type.\n");
+		parse_note_error(parse);
+	}
+
+	list_init(&symbol->attr);
+
+	/* Parse attributes. */
+	while (lcur_lc(parse) == lc_comma && !parse_is_error(parse)) {
+		lskip(parse);
+		attr = parse_symbol_attr(parse);
+		list_append(&symbol->attr, attr);
+	}
+
+	ctor->proc = stree_proc_new();
+	ctor->proc->outer_symbol = symbol;
+
+	if (lcur_lc(parse) == lc_scolon) {
+		lskip(parse);
+
+		/* This constructor has no body. */
+		printf("Error: Constructor of CSI '");
+		symbol_print_fqn(csi_to_symbol(outer_csi));
+		printf("' has no body.\n");
+		parse_note_error(parse);
+
+		ctor->proc->body = NULL;
+	} else {
+		lmatch(parse, lc_is);
+		ctor->proc->body = parse_block(parse);
+		lmatch(parse, lc_end);
+	}
+
+	return ctor;
+}
+
+/** Parse @c enum declaration.
+ *
+ * @param parse		Parser object.
+ * @param outer_csi	CSI containing this declaration or @c NULL if global.
+ * @return		New syntax tree node.
+ */
+static stree_enum_t *parse_enum(parse_t *parse, stree_csi_t *outer_csi)
+{
+	stree_enum_t *enum_d;
+	stree_symbol_t *symbol;
+	stree_embr_t *embr;
+
+	enum_d = stree_enum_new();
+	symbol = stree_symbol_new(sc_enum);
+
+	symbol->u.enum_d = enum_d;
+	symbol->outer_csi = outer_csi;
+	enum_d->symbol = symbol;
+
+	lmatch(parse, lc_enum);
+	enum_d->name = parse_ident(parse);
+	list_init(&enum_d->members);
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse enum '%s'.\n", strtab_get_str(enum_d->name->sid));
+#endif
+	lmatch(parse, lc_is);
+
+	/* Parse enum members. */
+	while (lcur_lc(parse) != lc_end && !parse_is_error(parse)) {
+		embr = parse_embr(parse, enum_d);
+		if (embr == NULL)
+			break;
+
+		list_append(&enum_d->members, embr);
+	}
+
+	if (list_is_empty(&enum_d->members)) {
+		printf("Error: Enum type '%s' has no members.\n",
+		    strtab_get_str(enum_d->name->sid));
+		parse_note_error(parse);
+	}
+
+	lmatch(parse, lc_end);
+
+	return enum_d;
+}
+
+/** Parse enum member.
+ *
+ * @param parse		Parser object.
+ * @param outer_enum	Enum containing this declaration.
+ * @return		New syntax tree node. In case of parse error,
+ *			@c NULL may (but need not) be returned.
+ */
+static stree_embr_t *parse_embr(parse_t *parse, stree_enum_t *outer_enum)
+{
+	stree_embr_t *embr;
+
+	embr = stree_embr_new();
+	embr->outer_enum = outer_enum;
+	embr->name = parse_ident(parse);
+
+	lmatch(parse, lc_scolon);
+
+	return embr;
 }
 
@@ -681,4 +845,5 @@
 	stree_for_t *for_s;
 	stree_raise_t *raise_s;
+	stree_break_t *break_s;
 	stree_return_t *return_s;
 	stree_wef_t *wef_s;
@@ -714,4 +879,9 @@
 		stat->u.raise_s = raise_s;
 		break;
+	case lc_break:
+		break_s = parse_break(parse);
+		stat = stree_stat_new(st_break);
+		stat->u.break_s = break_s;
+		break;
 	case lc_return:
 		return_s = parse_return(parse);
@@ -777,4 +947,5 @@
 {
 	stree_if_t *if_s;
+	stree_if_clause_t *if_c;
 
 #ifdef DEBUG_PARSE_TRACE
@@ -782,10 +953,28 @@
 #endif
 	if_s = stree_if_new();
-
+	list_init(&if_s->if_clauses);
+
+	/* Parse @c if clause. */
 	lmatch(parse, lc_if);
-	if_s->cond = parse_expr(parse);
+
+	if_c = stree_if_clause_new();
+	if_c->cond = parse_expr(parse);
 	lmatch(parse, lc_then);
-	if_s->if_block = parse_block(parse);
-
+	if_c->block = parse_block(parse);
+
+	list_append(&if_s->if_clauses, if_c);
+
+	/* Parse @c elif clauses. */
+	while (lcur_lc(parse) == lc_elif) {
+		lskip(parse);
+		if_c = stree_if_clause_new();
+		if_c->cond = parse_expr(parse);
+		lmatch(parse, lc_then);
+		if_c->block = parse_block(parse);
+
+		list_append(&if_s->if_clauses, if_c);
+	}
+
+	/* Parse @c else clause. */
 	if (lcur_lc(parse) == lc_else) {
 		lskip(parse);
@@ -867,4 +1056,24 @@
 }
 
+/** Parse @c break statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_break_t *parse_break(parse_t *parse)
+{
+	stree_break_t *break_s;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'break' statement.\n");
+#endif
+	break_s = stree_break_new();
+
+	lmatch(parse, lc_break);
+	lmatch(parse, lc_scolon);
+
+	return break_s;
+}
+
 /** Parse @c return statement.
  *
@@ -882,5 +1091,8 @@
 
 	lmatch(parse, lc_return);
-	return_s->expr = parse_expr(parse);
+
+	if (lcur_lc(parse) != lc_scolon)
+		return_s->expr = parse_expr(parse);
+
 	lmatch(parse, lc_scolon);
 
@@ -996,4 +1208,5 @@
 	ident = stree_ident_new();
 	ident->sid = lcur(parse)->u.ident.sid;
+	ident->cspan = lcur_span(parse);
 	lskip(parse);
 
@@ -1059,6 +1272,6 @@
 /** Return current lem lclass.
  *
- * @param parse		Parser object.
- * @return		Lclass of the current lem.
+ * @param parse		Parser object
+ * @return		Lclass of the current lem
  */
 lclass_t lcur_lc(parse_t *parse)
@@ -1081,4 +1294,42 @@
 }
 
+/** Return coordinate span of current lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of current lem or @c NULL if a
+ *			parse error is active
+ */
+cspan_t *lcur_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lcur(parse);
+	return lem->cspan;
+}
+
+/** Return coordinate span of previous lem.
+ *
+ * @param parse		Parser object
+ * @return		Coordinate span of previous lem or @c NULL if
+ * 			parse error is active or previous lem is not
+ *			available.
+ */
+cspan_t *lprev_span(parse_t *parse)
+{
+	lem_t *lem;
+
+	if (parse_is_error(parse))
+		return NULL;
+
+	lem = lex_peek_prev(parse->lex);
+	if (lem == NULL)
+		return NULL;
+
+	return lem->cspan;
+}
+
 /** Skip to next lem.
  *
@@ -1170,4 +1421,5 @@
 {
 	switch (lclass) {
+	case lc_elif:
 	case lc_else:
 	case lc_end:
Index: uspace/app/sbi/src/parse.h
===================================================================
--- uspace/app/sbi/src/parse.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/parse.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -48,4 +48,7 @@
 lem_t *lcur(parse_t *parse);
 lclass_t lcur_lc(parse_t *parse);
+cspan_t *lcur_span(parse_t *parse);
+cspan_t *lprev_span(parse_t *parse);
+
 void lskip(parse_t *parse);
 void lcheck(parse_t *parse, lclass_t lc);
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/rdata.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -52,4 +52,5 @@
 #include "stree.h"
 #include "symbol.h"
+#include "strtab.h"
 
 #include "rdata.h"
@@ -61,8 +62,10 @@
 static void rdata_ref_copy(rdata_ref_t *src, rdata_ref_t **dest);
 static void rdata_deleg_copy(rdata_deleg_t *src, rdata_deleg_t **dest);
+static void rdata_enum_copy(rdata_enum_t *src, rdata_enum_t **dest);
 static void rdata_array_copy(rdata_array_t *src, rdata_array_t **dest);
 static void rdata_object_copy(rdata_object_t *src, rdata_object_t **dest);
 static void rdata_resource_copy(rdata_resource_t *src,
     rdata_resource_t **dest);
+static void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_t **dest);
 
 static int rdata_array_get_dim(rdata_array_t *array);
@@ -247,4 +250,21 @@
 
 	return deleg;
+}
+
+/** Allocate new enum value.
+ *
+ * @return	New enum value.
+ */
+rdata_enum_t *rdata_enum_new(void)
+{
+	rdata_enum_t *enum_v;
+
+	enum_v = calloc(1, sizeof(rdata_enum_t));
+	if (enum_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return enum_v;
 }
 
@@ -373,4 +393,21 @@
 
 	return resource_v;
+}
+
+/** Allocate new symbol reference.
+ *
+ * @return	New symbol reference.
+ */
+rdata_symbol_t *rdata_symbol_new(void)
+{
+	rdata_symbol_t *symbol_v;
+
+	symbol_v = calloc(1, sizeof(rdata_symbol_t));
+	if (symbol_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return symbol_v;
 }
 
@@ -453,4 +490,7 @@
 		rdata_deleg_copy(src->u.deleg_v, &nvar->u.deleg_v);
 		break;
+	case vc_enum:
+		rdata_enum_copy(src->u.enum_v, &nvar->u.enum_v);
+		break;
 	case vc_array:
 		rdata_array_copy(src->u.array_v, &nvar->u.array_v);
@@ -461,4 +501,7 @@
 	case vc_resource:
 		rdata_resource_copy(src->u.resource_v, &nvar->u.resource_v);
+		break;
+	case vc_symbol:
+		rdata_symbol_copy(src->u.symbol_v, &nvar->u.symbol_v);
 		break;
 	}
@@ -534,4 +577,15 @@
 }
 
+/** Copy enum value.
+ *
+ * @param src		Source enum value.
+ * @param dest		Place to store pointer to new enum value.
+ */
+static void rdata_enum_copy(rdata_enum_t *src, rdata_enum_t **dest)
+{
+	*dest = rdata_enum_new();
+	(*dest)->value = src->value;
+}
+
 /** Copy array.
  *
@@ -567,4 +621,15 @@
 	*dest = rdata_resource_new();
 	(*dest)->data = src->data;
+}
+
+/** Copy symbol.
+ *
+ * @param src		Source symbol.
+ * @param dest		Place to store pointer to new symbol.
+ */
+static void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_t **dest)
+{
+	*dest = rdata_symbol_new();
+	(*dest)->sym = src->sym;
 }
 
@@ -621,7 +686,9 @@
 	case vc_ref: var->u.ref_v = nvar->u.ref_v; break;
 	case vc_deleg: var->u.deleg_v = nvar->u.deleg_v; break;
+	case vc_enum: var->u.enum_v = nvar->u.enum_v; break;
 	case vc_array: var->u.array_v = nvar->u.array_v; break;
 	case vc_object: var->u.object_v = nvar->u.object_v; break;
 	case vc_resource: var->u.resource_v = nvar->u.resource_v; break;
+	case vc_symbol: var->u.symbol_v = nvar->u.symbol_v; break;
 	}
 
@@ -732,4 +799,10 @@
 		printf(")");
 		break;
+	case vc_enum:
+		symbol_print_fqn(
+		    enum_to_symbol(var->u.enum_v->value->outer_enum));
+		printf(".%s",
+		    strtab_get_str(var->u.enum_v->value->name->sid));
+		break;
 	case vc_array:
 		printf("array");
@@ -741,4 +814,13 @@
 		printf("resource(%p)", var->u.resource_v->data);
 		break;
-	}
-}
+	case vc_symbol:
+		printf("symbol(");
+		if (var->u.symbol_v->sym != NULL) {
+			symbol_print_fqn(var->u.symbol_v->sym);
+		} else {
+			printf("nil");
+		}
+		printf(")");
+		break;
+	}
+}
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/rdata.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -43,4 +43,5 @@
 rdata_ref_t *rdata_ref_new(void);
 rdata_deleg_t *rdata_deleg_new(void);
+rdata_enum_t *rdata_enum_new(void);
 rdata_array_t *rdata_array_new(int rank);
 rdata_object_t *rdata_object_new(void);
@@ -50,4 +51,5 @@
 rdata_string_t *rdata_string_new(void);
 rdata_resource_t *rdata_resource_new(void);
+rdata_symbol_t *rdata_symbol_new(void);
 
 void rdata_array_alloc_element(rdata_array_t *array);
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/rdata_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -82,4 +82,10 @@
 } rdata_deleg_t;
 
+/** Enumerated type value. */
+typedef struct {
+	/** Enum member declaration */
+	struct stree_embr *value;
+} rdata_enum_t;
+
 /** Array variable */
 typedef struct {
@@ -116,4 +122,13 @@
 } rdata_resource_t;
 
+/** Symbol reference variable
+ *
+ * A symbol reference points to a program symbol.
+ */
+typedef struct {
+	/** Program symbol. */
+	struct stree_symbol *sym;
+} rdata_symbol_t;
+
 typedef enum var_class {
 	/** Boolean */
@@ -135,4 +150,7 @@
 	vc_deleg,
 
+	/** Enumerated type value */
+	vc_enum,
+
 	/** Array */
 	vc_array,
@@ -142,5 +160,8 @@
 
 	/** Interpreter builtin resource */
-	vc_resource
+	vc_resource,
+
+	/** Symbol reference */
+	vc_symbol
 } var_class_t;
 
@@ -161,7 +182,9 @@
 		rdata_ref_t *ref_v;
 		rdata_deleg_t *deleg_v;
+		rdata_enum_t *enum_v;
 		rdata_array_t *array_v;
 		rdata_object_t *object_v;
 		rdata_resource_t *resource_v;
+		rdata_symbol_t *symbol_v;
 	} u;
 } rdata_var_t;
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/run.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -34,4 +34,5 @@
 #include "bigint.h"
 #include "builtin.h"
+#include "cspan.h"
 #include "debug.h"
 #include "intmap.h"
@@ -54,4 +55,5 @@
 static void run_while(run_t *run, stree_while_t *while_s);
 static void run_raise(run_t *run, stree_raise_t *raise_s);
+static void run_break(run_t *run, stree_break_t *break_s);
 static void run_return(run_t *run, stree_return_t *return_s);
 static void run_wef(run_t *run, stree_wef_t *wef_s);
@@ -71,5 +73,6 @@
 static void run_var_new_null_ref(run_t *run, rdata_var_t **rvar);
 static void run_var_new_deleg(run_t *run, rdata_var_t **rvar);
-
+static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
+    rdata_var_t **rvar);
 
 /** Initialize runner instance.
@@ -177,6 +180,6 @@
 	switch (run->thread_ar->bo_mode) {
 	case bm_stat:
-		printf("Error: Misplaced 'break' statement.\n");
-		exit(1);
+		/* Break bailout was not caught. */
+		assert(b_false);
 	case bm_proc:
 		run->thread_ar->bo_mode = bm_none;
@@ -283,4 +286,7 @@
 		run_raise(run, stat->u.raise_s);
 		break;
+	case st_break:
+		run_break(run, stat->u.break_s);
+		break;
 	case st_return:
 		run_return(run, stat->u.return_s);
@@ -292,6 +298,4 @@
 		printf("Ignoring unimplemented statement type %d.\n", stat->sc);
 		break;
-	default:
-		assert(b_false);
 	}
 }
@@ -364,23 +368,42 @@
 {
 	rdata_item_t *rcond;
+	list_node_t *ifc_node;
+	stree_if_clause_t *ifc;
+	bool_t clause_fired;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Executing if statement.\n");
 #endif
-	run_expr(run, if_s->cond, &rcond);
-	if (run_is_bo(run))
-		return;
-
-	if (run_item_boolean_value(run, rcond) == b_true) {
-#ifdef DEBUG_RUN_TRACE
-		printf("Taking true path.\n");
-#endif
-		run_block(run, if_s->if_block);
-	} else {
-#ifdef DEBUG_RUN_TRACE
-		printf("Taking false path.\n");
-#endif
-        	if (if_s->else_block != NULL)
-			run_block(run, if_s->else_block);
+	clause_fired = b_false;
+	ifc_node = list_first(&if_s->if_clauses);
+
+	/* Walk through all if/elif clauses and see if they fire. */
+
+	while (ifc_node != NULL) {
+		/* Get if/elif clause */
+		ifc = list_node_data(ifc_node, stree_if_clause_t *);
+
+		run_expr(run, ifc->cond, &rcond);
+		if (run_is_bo(run))
+			return;
+
+		if (run_item_boolean_value(run, rcond) == b_true) {
+#ifdef DEBUG_RUN_TRACE
+			printf("Taking non-default path.\n");
+#endif
+			run_block(run, ifc->block);
+			clause_fired = b_true;
+			break;
+		}
+
+		ifc_node = list_next(&if_s->if_clauses, ifc_node);
+	}
+
+	/* If no if/elif clause fired, invoke the else clause. */
+	if (clause_fired == b_false && if_s->else_block != NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking default path.\n");
+#endif
+		run_block(run, if_s->else_block);
 	}
 
@@ -410,8 +433,10 @@
 		run_expr(run, while_s->cond, &rcond);
 		if (run_is_bo(run))
-			return;
-
-		if (run->thread_ar->bo_mode != bm_none)
 			break;
+	}
+
+	if (run->thread_ar->bo_mode == bm_stat) {
+		/* Bailout due to break statement */
+		run->thread_ar->bo_mode = bm_none;
 	}
 
@@ -440,4 +465,7 @@
 	run_cvt_value_item(run, rexpr, &rexpr_vi);
 
+	/* Store expression cspan in thread AR. */
+	run->thread_ar->exc_cspan = raise_s->expr->cspan;
+
 	/* Store expression result in thread AR. */
 	run->thread_ar->exc_payload = rexpr_vi->u.value;
@@ -447,4 +475,24 @@
 }
 
+/** Run @c break statement.
+ *
+ * Forces control to return from the active breakable statement by setting
+ * bailout mode to @c bm_stat.
+ *
+ * @param run		Runner object
+ * @param break_s	Break statement to run
+ */
+static void run_break(run_t *run, stree_break_t *break_s)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing 'break' statement.\n");
+#endif
+	(void) break_s;
+
+	/* Force control to ascend and leave the procedure. */
+	if (run->thread_ar->bo_mode == bm_none)
+		run->thread_ar->bo_mode = bm_stat;
+}
+
 /** Run @c return statement.
  *
@@ -453,5 +501,5 @@
  *
  * @param run		Runner object
- * @param raise_s	Return statement to run
+ * @param return_s	Return statement to run
  */
 static void run_return(run_t *run, stree_return_t *return_s)
@@ -464,13 +512,15 @@
 	printf("Executing return statement.\n");
 #endif
-	run_expr(run, return_s->expr, &rexpr);
-	if (run_is_bo(run))
-		return;
-
-	run_cvt_value_item(run, rexpr, &rexpr_vi);
-
-	/* Store expression result in procedure AR. */
-	proc_ar = run_get_current_proc_ar(run);
-	proc_ar->retval = rexpr_vi;
+	if (return_s->expr != NULL) {
+		run_expr(run, return_s->expr, &rexpr);
+		if (run_is_bo(run))
+			return;
+
+		run_cvt_value_item(run, rexpr, &rexpr_vi);
+
+		/* Store expression result in procedure AR. */
+		proc_ar = run_get_current_proc_ar(run);
+		proc_ar->retval = rexpr_vi;
+	}
 
 	/* Force control to ascend and leave the procedure. */
@@ -632,4 +682,9 @@
 		exc_csi = run_exc_payload_get_csi(run);
 
+		if (run->thread_ar->exc_cspan != NULL) {
+			cspan_print(run->thread_ar->exc_cspan);
+			putchar(' ');
+		}
+
 		printf("Error: Unhandled exception '");
 		symbol_print_fqn(csi_to_symbol(exc_csi));
@@ -749,4 +804,5 @@
 	rdata_char_t *char_v;
 	rdata_deleg_t *deleg_v;
+	rdata_enum_t *enum_v;
 	rdata_int_t *int_v;
 	rdata_string_t *string_v;
@@ -780,4 +836,11 @@
 		deleg_v->obj = item->u.value->var->u.deleg_v->obj;
 		deleg_v->sym = item->u.value->var->u.deleg_v->sym;
+		break;
+	case vc_enum:
+		*var = rdata_var_new(vc_enum);
+		enum_v = rdata_enum_new();
+
+		(*var)->u.enum_v = enum_v;
+		enum_v->value = item->u.value->var->u.enum_v->value;
 		break;
 	case vc_int:
@@ -854,4 +917,5 @@
 void run_proc_ar_set_args(run_t *run, run_proc_ar_t *proc_ar, list_t *arg_vals)
 {
+	stree_ctor_t *ctor;
 	stree_fun_t *fun;
 	stree_prop_t *prop;
@@ -878,4 +942,8 @@
 	outer_symbol = proc_ar->proc->outer_symbol;
 
+	/* Make compiler happy. */
+	args = NULL;
+	varg = NULL;
+
 	/*
 	 * The procedure being activated should belong to a member function or
@@ -883,4 +951,9 @@
 	 */
 	switch (outer_symbol->sc) {
+	case sc_ctor:
+		ctor = symbol_to_ctor(outer_symbol);
+		args = &ctor->sig->args;
+		varg = ctor->sig->varg;
+		break;
 	case sc_fun:
 		fun = symbol_to_fun(outer_symbol);
@@ -893,5 +966,8 @@
 		varg = prop->varg;
 		break;
-	default:
+	case sc_csi:
+	case sc_deleg:
+	case sc_enum:
+	case sc_var:
 		assert(b_false);
 	}
@@ -1377,7 +1453,10 @@
  * @param run		Runner object
  * @param ref		Reference
+ * @param cspan		Cspan to put into exception if reference is nil
+ *			or @c NULL if no cspan is provided.
  * @param rtitem	Place to store pointer to the resulting address.
  */
-void run_dereference(run_t *run, rdata_item_t *ref, rdata_item_t **ritem)
+void run_dereference(run_t *run, rdata_item_t *ref, cspan_t *cspan,
+    rdata_item_t **ritem)
 {
 	rdata_item_t *ref_val;
@@ -1404,5 +1483,6 @@
 #endif
 		/* Raise Error.NilReference */
-		run_raise_exc(run, run->program->builtin->error_nilreference);
+		run_raise_exc(run, run->program->builtin->error_nilreference,
+		    cspan);
 		*ritem = run_recovery_item(run);
 		return;
@@ -1422,8 +1502,12 @@
  * @param run		Runner object
  * @param csi		Exception class
- */
-void run_raise_exc(run_t *run, stree_csi_t *csi)
+ * @param cspan		Cspan of code that caused exception (for debugging)
+ */
+void run_raise_exc(run_t *run, stree_csi_t *csi, cspan_t *cspan)
 {
 	rdata_item_t *exc_vi;
+
+	/* Store exception cspan in thread AR. */
+	run->thread_ar->exc_cspan = cspan;
 
 	/* Create exception object. */
@@ -1472,4 +1556,15 @@
 		break;
 	case tic_tdeleg:
+		run_var_new_deleg(run, rvar);
+		break;
+	case tic_tebase:
+		/*
+		 * One cannot declare variable of ebase type. It is just
+		 * type of expressions referring to enum types.
+		 */
+		assert(b_false);
+	case tic_tenum:
+		run_var_new_enum(run, ti->u.tenum, rvar);
+		break;
 	case tic_tfun:
 		run_var_new_deleg(run, rvar);
@@ -1578,4 +1673,32 @@
 }
 
+/** Construct a new variable containing default value of an enum type.
+ *
+ * @param run		Runner object
+ * @param rvar		Place to store pointer to new variable
+ */
+static void run_var_new_enum(run_t *run, tdata_enum_t *tenum,
+    rdata_var_t **rvar)
+{
+	rdata_var_t *var;
+	list_node_t *embr_n;
+	stree_embr_t *embr;
+
+	(void) run;
+
+	/* Get first member of enum which will serve as default value. */
+	embr_n = list_first(&tenum->enum_d->members);
+	assert(embr_n != NULL);
+
+	embr = list_node_data(embr_n, stree_embr_t *);
+
+	/* Return null reference. */
+	var = rdata_var_new(vc_enum);
+	var->u.enum_v = rdata_enum_new();
+	var->u.enum_v->value = embr;
+
+	*rvar = var;
+}
+
 /** Construct a new thread activation record.
  *
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/run.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -63,7 +63,8 @@
     rdata_value_t *value);
 void run_reference(run_t *run, rdata_var_t *var, rdata_item_t **res);
-void run_dereference(run_t *run, rdata_item_t *ref, rdata_item_t **ritem);
+void run_dereference(run_t *run, rdata_item_t *ref, cspan_t *cspan,
+    rdata_item_t **ritem);
 
-void run_raise_exc(run_t *run, stree_csi_t *csi);
+void run_raise_exc(run_t *run, stree_csi_t *csi, cspan_t *cspan);
 bool_t run_is_bo(run_t *run);
 
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/run_expr.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -78,6 +78,10 @@
 static void run_binop_ref(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
     rdata_value_t *v2, rdata_item_t **res);
+static void run_binop_enum(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res);
 
 static void run_unop(run_t *run, stree_unop_t *unop, rdata_item_t **res);
+static void run_unop_bool(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    rdata_item_t **res);
 static void run_unop_int(run_t *run, stree_unop_t *unop, rdata_value_t *val,
     rdata_item_t **res);
@@ -88,4 +92,6 @@
 static void run_new_object(run_t *run, stree_new_t *new_op,
     tdata_item_t *titem, rdata_item_t **res);
+
+static void run_object_ctor(run_t *run, rdata_var_t *obj, list_t *arg_vals);
 
 static void run_access(run_t *run, stree_access_t *access, rdata_item_t **res);
@@ -98,6 +104,10 @@
 static void run_access_object(run_t *run, stree_access_t *access,
     rdata_item_t *arg, rdata_item_t **res);
+static void run_access_symbol(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res);
 
 static void run_call(run_t *run, stree_call_t *call, rdata_item_t **res);
+static void run_call_args(run_t *run, list_t *args, list_t *arg_vals);
+
 static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res);
 static void run_index_array(run_t *run, stree_index_t *index,
@@ -189,4 +199,5 @@
 	rdata_var_t *var;
 	rdata_deleg_t *deleg_v;
+	rdata_symbol_t *symbol_v;
 
 	run_proc_ar_t *proc_ar;
@@ -246,5 +257,5 @@
 	case sc_csi:
 #ifdef DEBUG_RUN_TRACE
-		printf("Referencing class.\n");
+		printf("Referencing CSI.\n");
 #endif
 		item = rdata_item_new(ic_value);
@@ -260,4 +271,28 @@
 		deleg_v->sym = sym;
 		*res = item;
+		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_enum:
+#ifdef DEBUG_RUN_TRACE
+		printf("Referencing enum.\n");
+#endif
+		item = rdata_item_new(ic_value);
+		value = rdata_value_new();
+		var = rdata_var_new(vc_symbol);
+		symbol_v = rdata_symbol_new();
+
+		item->u.value = value;
+		value->var = var;
+		var->u.symbol_v = symbol_v;
+
+		symbol_v->sym = sym;
+		*res = item;
+		break;
+	case sc_deleg:
+		/* XXX TODO */
+		printf("Unimplemented: Delegate name reference.\n");
+		abort();
 		break;
 	case sc_fun:
@@ -329,7 +364,8 @@
 		*res = item;
 		break;
-	default:
-		printf("Referencing symbol class %d unimplemented.\n", sym->sc);
-		*res = NULL;
+	case sc_prop:
+		/* XXX TODO */
+		printf("Unimplemented: Property name reference.\n");
+		abort();
 		break;
 	}
@@ -571,22 +607,4 @@
 	}
 
-	switch (binop->bc) {
-	case bo_plus:
-	case bo_minus:
-	case bo_mult:
-	case bo_equal:
-	case bo_notequal:
-	case bo_lt:
-	case bo_gt:
-	case bo_lt_equal:
-	case bo_gt_equal:
-		/* These are implemented so far. */
-		break;
-	default:
-		printf("Unimplemented: Binary operation type %d.\n",
-		    binop->bc);
-		exit(1);
-	}
-
 #ifdef DEBUG_RUN_TRACE
 	printf("Check binop argument results.\n");
@@ -621,8 +639,12 @@
 		run_binop_ref(run, binop, v1, v2, res);
 		break;
+	case vc_enum:
+		run_binop_enum(run, binop, v1, v2, res);
+		break;
 	case vc_deleg:
 	case vc_array:
 	case vc_object:
 	case vc_resource:
+	case vc_symbol:
 		assert(b_false);
 	}
@@ -685,4 +707,11 @@
 		bool_v->value = (b1 == b_true) || (b2 == b_false);
 		break;
+
+	case bo_and:
+		bool_v->value = (b1 == b_true) && (b2 == b_true);
+		break;
+	case bo_or:
+		bool_v->value = (b1 == b_true) || (b2 == b_true);
+		break;
 	}
 
@@ -753,5 +782,7 @@
 		bool_v->value = !nf;
 		break;
-	default:
+
+	case bo_and:
+	case bo_or:
 		assert(b_false);
 	}
@@ -832,4 +863,9 @@
 
 	switch (binop->bc) {
+	case bo_plus:
+	case bo_minus:
+	case bo_mult:
+		assert(b_false);
+
 	case bo_equal:
 		bool_v->value = zf;
@@ -850,5 +886,6 @@
 		bool_v->value = !nf;
 		break;
-	default:
+	case bo_and:
+	case bo_or:
 		assert(b_false);
 	}
@@ -872,4 +909,7 @@
 	rdata_var_t *var;
 	rdata_string_t *string_v;
+	rdata_bool_t *bool_v;
+	bool_t done;
+	bool_t zf;
 
 	const char *s1, *s2;
@@ -879,18 +919,46 @@
 	item = rdata_item_new(ic_value);
 	value = rdata_value_new();
-	var = rdata_var_new(vc_string);
-	string_v = rdata_string_new();
 
 	item->u.value = value;
-	value->var = var;
-	var->u.string_v = string_v;
 
 	s1 = v1->var->u.string_v->value;
 	s2 = v2->var->u.string_v->value;
+
+	done = b_true;
 
 	switch (binop->bc) {
 	case bo_plus:
 		/* Concatenate strings. */
+		string_v = rdata_string_new();
 		string_v->value = os_str_acat(s1, s2);
+		break;
+	default:
+		done = b_false;
+		break;
+	}
+
+	if (done) {
+		var = rdata_var_new(vc_string);
+		var->u.string_v = string_v;
+		value->var = var;
+		*res = item;
+		return;
+	}
+
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+	var->u.bool_v = bool_v;
+	value->var = var;
+
+	/* Relational operation. */
+
+	zf = os_str_cmp(s1, s2) == 0;
+
+	switch (binop->bc) {
+	case bo_equal:
+		bool_v->value = zf;
+		break;
+	case bo_notequal:
+		bool_v->value = !zf;
 		break;
 	default:
@@ -951,4 +1019,50 @@
 }
 
+/** Evaluate binary operation on enum arguments.
+ *
+ * @param run		Runner object
+ * @param binop		Binary operation
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result
+ */
+static void run_binop_enum(run_t *run, stree_binop_t *binop, rdata_value_t *v1,
+    rdata_value_t *v2, rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_bool_t *bool_v;
+
+	rdata_var_t *ref1, *ref2;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	ref1 = v1->var->u.ref_v->vref;
+	ref2 = v2->var->u.ref_v->vref;
+
+	switch (binop->bc) {
+	case bo_equal:
+		bool_v->value = (ref1 == ref2);
+		break;
+	case bo_notequal:
+		bool_v->value = (ref1 != ref2);
+		break;
+	default:
+		/* Should have been caught by static typing. */
+		assert(b_false);
+	}
+
+	*res = item;
+}
 
 /** Evaluate unary operation.
@@ -981,4 +1095,7 @@
 
 	switch (val->var->vc) {
+	case vc_bool:
+		run_unop_bool(run, unop, val, res);
+		break;
 	case vc_int:
 		run_unop_int(run, unop, val, res);
@@ -993,4 +1110,43 @@
 }
 
+/** Evaluate unary operation on bool argument.
+ *
+ * @param run		Runner object
+ * @param unop		Unary operation
+ * @param val		Value of argument
+ * @param res		Place to store result
+ */
+static void run_unop_bool(run_t *run, stree_unop_t *unop, rdata_value_t *val,
+    rdata_item_t **res)
+{
+	rdata_item_t *item;
+	rdata_value_t *value;
+	rdata_var_t *var;
+	rdata_bool_t *bool_v;
+
+	(void) run;
+
+	item = rdata_item_new(ic_value);
+	value = rdata_value_new();
+	var = rdata_var_new(vc_bool);
+	bool_v = rdata_bool_new();
+
+	item->u.value = value;
+	value->var = var;
+	var->u.bool_v = bool_v;
+
+	switch (unop->uc) {
+	case uo_plus:
+	case uo_minus:
+		assert(b_false);
+
+	case uo_not:
+		bool_v->value = !val->var->u.bool_v->value;
+		break;
+	}
+
+	*res = item;
+}
+
 /** Evaluate unary operation on int argument.
  *
@@ -1027,9 +1183,10 @@
 		    &int_v->value);
 		break;
+	case uo_not:
+		assert(b_false);
 	}
 
 	*res = item;
 }
-
 
 /** Evaluate @c new operation.
@@ -1186,16 +1343,29 @@
 {
 	stree_csi_t *csi;
+	rdata_item_t *obj_i;
+	list_t arg_vals;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Create new object.\n");
 #endif
-	(void) new_op;
-
 	/* Lookup object CSI. */
 	assert(titem->tic == tic_tobject);
 	csi = titem->u.tobject->csi;
 
+	/* Evaluate constructor arguments. */
+	run_call_args(run, &new_op->ctor_args, &arg_vals);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
 	/* Create CSI instance. */
 	run_new_csi_inst(run, csi, res);
+
+	/* Run the constructor. */
+	run_dereference(run, *res, NULL, &obj_i);
+	assert(obj_i->ic == ic_address);
+	assert(obj_i->u.address->ac == ac_var);
+	run_object_ctor(run, obj_i->u.address->u.var_a->vref, &arg_vals);
 }
 
@@ -1256,5 +1426,15 @@
 		run_access_object(run, access, arg, res);
 		break;
-	default:
+	case vc_symbol:
+		run_access_symbol(run, access, arg, res);
+		break;
+
+	case vc_bool:
+	case vc_char:
+	case vc_enum:
+	case vc_int:
+	case vc_string:
+	case vc_array:
+	case vc_resource:
 		printf("Unimplemented: Using access operator ('.') "
 		    "with unsupported data type (value/%d).\n", vc);
@@ -1276,5 +1456,5 @@
 
 	/* Implicitly dereference. */
-	run_dereference(run, arg, &darg);
+	run_dereference(run, arg, access->arg->cspan, &darg);
 
 	if (run->thread_ar->bo_mode != bm_none) {
@@ -1396,4 +1576,10 @@
 		printf("Error: Accessing object member which is a delegate.\n");
 		exit(1);
+	case sc_enum:
+		printf("Error: Accessing object member which is an enum.\n");
+		exit(1);
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
 	case sc_fun:
 		/* Construct anonymous delegate. */
@@ -1442,4 +1628,59 @@
 }
 
+/** Evaluate symbol member acccess.
+ *
+ * @param run		Runner object
+ * @param access	Access operation
+ * @param arg		Evaluated base expression
+ * @param res		Place to store result
+ */
+static void run_access_symbol(run_t *run, stree_access_t *access,
+    rdata_item_t *arg, rdata_item_t **res)
+{
+	rdata_item_t *arg_vi;
+	rdata_value_t *arg_val;
+	rdata_symbol_t *symbol_v;
+	stree_embr_t *embr;
+
+	rdata_item_t *ritem;
+	rdata_value_t *rvalue;
+	rdata_var_t *rvar;
+	rdata_enum_t *enum_v;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run symbol access operation.\n");
+#endif
+	run_cvt_value_item(run, arg, &arg_vi);
+	arg_val = arg_vi->u.value;
+	assert(arg_val->var->vc == vc_symbol);
+
+	symbol_v = arg_val->var->u.symbol_v;
+
+	/* XXX Port CSI symbol reference to using vc_symbol */
+	assert(symbol_v->sym->sc == sc_enum);
+
+	embr = stree_enum_find_mbr(symbol_v->sym->u.enum_d,
+	    access->member_name);
+
+	/* Member existence should be ensured by static type checking. */
+	assert(embr != NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found enum member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+	ritem = rdata_item_new(ic_value);
+	rvalue = rdata_value_new();
+	rvar = rdata_var_new(vc_enum);
+	enum_v = rdata_enum_new();
+
+	ritem->u.value = rvalue;
+	rvalue->var = rvar;
+	rvar->u.enum_v = enum_v;
+	enum_v->value = embr;
+
+	*res = ritem;
+}
+
 /** Call a function.
  *
@@ -1455,7 +1696,4 @@
 	rdata_deleg_t *deleg_v;
 	list_t arg_vals;
-	list_node_t *node;
-	stree_expr_t *arg;
-	rdata_item_t *rarg_i, *rarg_vi;
 
 	stree_fun_t *fun;
@@ -1499,6 +1737,111 @@
 #endif
 	/* Evaluate function arguments. */
+	run_call_args(run, &call->args, &arg_vals);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	fun = symbol_to_fun(deleg_v->sym);
+	assert(fun != NULL);
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, deleg_v->obj, fun->proc, &proc_ar);
+
+	/* Fill in argument values. */
+	run_proc_ar_set_args(run, proc_ar, &arg_vals);
+
+	/* Run the function. */
+	run_proc(run, proc_ar, res);
+
+	if (!run_is_bo(run) && fun->sig->rtype != NULL && *res == NULL) {
+		printf("Error: Function '");
+		symbol_print_fqn(deleg_v->sym);
+		printf("' did not return a value.\n");
+		exit(1);
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Returned from function call.\n");
+#endif
+}
+
+/** Evaluate call arguments.
+ *
+ * Evaluate arguments to function or constructor.
+ *
+ * @param run		Runner object
+ * @param args		Real arguments (list of stree_expr_t)
+ * @param arg_vals	Address of uninitialized list to store argument values
+ *			(list of rdata_item_t).
+ */
+static void run_call_args(run_t *run, list_t *args, list_t *arg_vals)
+{
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	rdata_item_t *rarg_i, *rarg_vi;
+
+	/* Evaluate function arguments. */
+	list_init(arg_vals);
+	arg_n = list_first(args);
+
+	while (arg_n != NULL) {
+		arg = list_node_data(arg_n, stree_expr_t *);
+		run_expr(run, arg, &rarg_i);
+		if (run_is_bo(run))
+			return;
+
+		run_cvt_value_item(run, rarg_i, &rarg_vi);
+
+		list_append(arg_vals, rarg_vi);
+		arg_n = list_next(args, arg_n);
+	}
+}
+
+/** Run index operation.
+ *
+ * Evaluate operation per the indexing ('[', ']') operator.
+ *
+ * @param run		Runner object
+ * @param index		Index operation
+ * @param res		Place to store result
+ */
+static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res)
+{
+	rdata_item_t *rbase;
+	rdata_item_t *base_i;
+	list_node_t *node;
+	stree_expr_t *arg;
+	rdata_item_t *rarg_i, *rarg_vi;
+	var_class_t vc;
+	list_t arg_vals;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run index operation.\n");
+#endif
+	run_expr(run, index->base, &rbase);
+	if (run_is_bo(run)) {
+		*res = NULL;
+		return;
+	}
+
+	vc = run_item_get_vc(run, rbase);
+
+	/* Implicitly dereference. */
+	if (vc == vc_ref) {
+		run_dereference(run, rbase, index->base->cspan, &base_i);
+		if (run_is_bo(run)) {
+			*res = NULL;
+			return;
+		}
+	} else {
+		base_i = rbase;
+	}
+
+	vc = run_item_get_vc(run, base_i);
+
+	/* Evaluate arguments (indices). */
+	node = list_first(&index->args);
 	list_init(&arg_vals);
-	node = list_first(&call->args);
 
 	while (node != NULL) {
@@ -1513,77 +1856,4 @@
 
 		list_append(&arg_vals, rarg_vi);
-		node = list_next(&call->args, node);
-	}
-
-	fun = symbol_to_fun(deleg_v->sym);
-	assert(fun != NULL);
-
-	/* Create procedure activation record. */
-	run_proc_ar_create(run, deleg_v->obj, fun->proc, &proc_ar);
-
-	/* Fill in argument values. */
-	run_proc_ar_set_args(run, proc_ar, &arg_vals);
-
-	/* Run the function. */
-	run_proc(run, proc_ar, res);
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Returned from function call.\n");
-#endif
-}
-
-/** Run index operation.
- *
- * Evaluate operation per the indexing ('[', ']') operator.
- *
- * @param run		Runner object
- * @param index		Index operation
- * @param res		Place to store result
- */
-static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res)
-{
-	rdata_item_t *rbase;
-	rdata_item_t *base_i;
-	list_node_t *node;
-	stree_expr_t *arg;
-	rdata_item_t *rarg_i, *rarg_vi;
-	var_class_t vc;
-	list_t arg_vals;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Run index operation.\n");
-#endif
-	run_expr(run, index->base, &rbase);
-	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
-	}
-
-	vc = run_item_get_vc(run, rbase);
-
-	/* Implicitly dereference. */
-	if (vc == vc_ref) {
-		run_dereference(run, rbase, &base_i);
-	} else {
-		base_i = rbase;
-	}
-
-	vc = run_item_get_vc(run, base_i);
-
-	/* Evaluate arguments (indices). */
-	node = list_first(&index->args);
-	list_init(&arg_vals);
-
-	while (node != NULL) {
-		arg = list_node_data(node, stree_expr_t *);
-		run_expr(run, arg, &rarg_i);
-		if (run_is_bo(run)) {
-			*res = NULL;
-			return;
-		}
-
-		run_cvt_value_item(run, rarg_i, &rarg_vi);
-
-		list_append(&arg_vals, rarg_vi);
 
 		node = list_next(&index->args, node);
@@ -1634,5 +1904,4 @@
 #endif
 	(void) run;
-	(void) index;
 
 	assert(base->ic == ic_address);
@@ -1676,5 +1945,7 @@
 			/* Raise Error.OutOfBounds */
 			run_raise_exc(run,
-			    run->program->builtin->error_outofbounds);
+			    run->program->builtin->error_outofbounds,
+			    index->expr->cspan);
+			/* XXX It should be cspan of the argument. */
 			*res = run_recovery_item(run);
 			return;
@@ -1814,5 +2085,4 @@
 #endif
 	(void) run;
-	(void) index;
 
 	run_cvt_value_item(run, base, &base_vi);
@@ -1866,5 +2136,6 @@
 #endif
 		/* Raise Error.OutOfBounds */
-		run_raise_exc(run, run->program->builtin->error_outofbounds);
+		run_raise_exc(run, run->program->builtin->error_outofbounds,
+		    index->expr->cspan);
 		*res = run_recovery_item(run);
 		return;
@@ -1970,5 +2241,5 @@
 	}
 
-	run_dereference(run, rarg_vi, &rarg_di);
+	run_dereference(run, rarg_vi, NULL, &rarg_di);
 
 	/* Now we should have a variable address. */
@@ -2048,7 +2319,9 @@
 	case vc_ref:
 	case vc_deleg:
+	case vc_enum:
 	case vc_array:
 	case vc_object:
 	case vc_resource:
+	case vc_symbol:
 		assert(b_false);
 	}
@@ -2147,4 +2420,61 @@
 }
 
+/** Run constructor on an object.
+ *
+ * @param run		Runner object
+ * @param obj		Object to run constructor on
+ * @param arg_vals	Argument values (list of rdata_item_t)
+ */
+static void run_object_ctor(run_t *run, rdata_var_t *obj, list_t *arg_vals)
+{
+	stree_ident_t *ctor_ident;
+	stree_symbol_t *csi_sym;
+	stree_csi_t *csi;
+	stree_symbol_t *ctor_sym;
+	stree_ctor_t *ctor;
+	run_proc_ar_t *proc_ar;
+	rdata_item_t *res;
+
+	csi_sym = obj->u.object_v->class_sym;
+	csi = symbol_to_csi(csi_sym);
+	assert(csi != NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run object constructor from CSI '");
+	symbol_print_fqn(csi_sym);
+	printf("'.\n");
+#endif
+	ctor_ident = stree_ident_new();
+	ctor_ident->sid = strtab_get_sid(CTOR_IDENT);
+
+	/* Find constructor. */
+	ctor_sym = symbol_search_csi_no_base(run->program, csi, ctor_ident);
+	if (ctor_sym == NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("No constructor found.\n");
+#endif
+		return;
+	}
+
+	ctor = symbol_to_ctor(ctor_sym);
+	assert(ctor != NULL);
+
+	/* Create procedure activation record. */
+	run_proc_ar_create(run, obj, ctor->proc, &proc_ar);
+
+	/* Fill in argument values. */
+	run_proc_ar_set_args(run, proc_ar, arg_vals);
+
+	/* Run the procedure. */
+	run_proc(run, proc_ar, &res);
+
+	/* Constructor does not return a value. */
+	assert(res == NULL);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Returned from constructor..\n");
+#endif
+}
+
 /** Return boolean value of an item.
  *
Index: uspace/app/sbi/src/run_t.h
===================================================================
--- uspace/app/sbi/src/run_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/run_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -97,4 +97,7 @@
 	run_bailout_mode_t bo_mode;
 
+	/** Exception cspan */
+	struct cspan *exc_cspan;
+
 	/** Exception payload */
 	struct rdata_value *exc_payload;
Index: uspace/app/sbi/src/run_texpr.c
===================================================================
--- uspace/app/sbi/src/run_texpr.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/run_texpr.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -31,4 +31,5 @@
 #include <assert.h>
 #include <stdlib.h>
+#include "cspan.h"
 #include "debug.h"
 #include "list.h"
@@ -102,4 +103,7 @@
 	tdata_deleg_t *tdeleg;
 	stree_csi_t *base_csi;
+	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
+	tdata_enum_t *tenum;
 
 #ifdef DEBUG_RUN_TRACE
@@ -115,5 +119,7 @@
 
 	if (targ_i->tic != tic_tobject) {
-		printf("Error: Using '.' with type which is not an object.\n");
+		cspan_print(taccess->texpr->cspan);
+		printf(" Error: Using '.' with type which is not an "
+		    "object.\n");
 		*res = tdata_item_new(tic_ignore);
 		return;
@@ -125,5 +131,6 @@
 	sym = symbol_lookup_in_csi(prog, base_csi, taccess->member_name);
 	if (sym == NULL) {
-		printf("Error: CSI '");
+		cspan_print(taccess->member_name->cspan);
+		printf(" Error: CSI '");
 		symbol_print_fqn(csi_to_symbol(base_csi));
 		printf("' has no member named '%s'.\n",
@@ -142,172 +149,9 @@
 		tobject->static_ref = b_false;
 		tobject->csi = sym->u.csi;
-		list_init(&tobject->targs); /* XXX */
-		break;
-	case sc_deleg:
-		/* Construct type item. */
-		titem = tdata_item_new(tic_tdeleg);
-		tdeleg = tdata_deleg_new();
-		titem->u.tdeleg = tdeleg;
-
-		tdeleg->deleg = sym->u.deleg;
-		break;
-	case sc_fun:
-	case sc_var:
-	case sc_prop:
-		printf("Error: Symbol '");
-		symbol_print_fqn(sym);
-		printf("' is not a type.\n");
-		titem = tdata_item_new(tic_ignore);
-		break;
-	}
-
-	*res = titem;
-}
-
-/** Evaluate type indexing expression.
- *
- * Evaluate operation per the type indexing ('[', ']') operator.
- * A type indexing operation may have extents specified or only rank
- * specified.
- *
- * @param prog		Program
- * @param ctx		Current CSI (context)
- * @param tindex	Type indexing expression to evaluate
- * @param res		Place to store type result
- */
-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;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Evaluating type index operation.\n");
-#endif
-	/* Evaluate base type. */
-	run_texpr(prog, ctx, tindex->base_type, &base_ti);
-
-	if (base_ti->tic == tic_ignore) {
-		*res = tdata_item_new(tic_ignore);
-		return;
-	}
-
-	/* Construct type item. */
-	titem = tdata_item_new(tic_tarray);
-	tarray = tdata_array_new();
-	titem->u.tarray = tarray;
-
-	tarray->base_ti = base_ti;
-	tarray->rank = tindex->n_args;
-
-	/* Copy extents. */
-	list_init(&tarray->extents);
-	arg_node = list_first(&tindex->args);
-
-	while (arg_node != NULL) {
-		arg_expr = list_node_data(arg_node, stree_expr_t *);
-		list_append(&tarray->extents, arg_expr);
-		arg_node = list_next(&tindex->args, arg_node);
-	}
-
-	*res = titem;
-}
-
-/** Evaluate type literal expression.
- *
- * @param prog		Program
- * @param ctx		Current CSI (context)
- * @param tliteral	Type literal
- * @param res		Place to store type result
- */
-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) prog;
-	(void) ctx;
-	(void) tliteral;
-
-	switch (tliteral->tlc) {
-	case tlc_bool: tpc = tpc_bool; break;
-	case tlc_char: tpc = tpc_char; break;
-	case tlc_int: tpc = tpc_int; break;
-	case tlc_string: tpc = tpc_string; break;
-	case tlc_resource: tpc = tpc_resource; break;
-	}
-
-	/* Construct type item. */
-	titem = tdata_item_new(tic_tprimitive);
-	tprimitive = tdata_primitive_new(tpc);
-	titem->u.tprimitive = tprimitive;
-
-	*res = titem;
-}
-
-static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
-    stree_tnameref_t *tnameref, tdata_item_t **res)
-{
-	stree_symbol_t *sym;
-	tdata_item_t *titem;
-	tdata_object_t *tobject;
-	stree_targ_t *targ;
-	tdata_vref_t *tvref;
-	stree_deleg_t *deleg;
-	tdata_deleg_t *tdeleg;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Evaluating type name reference.\n");
-	printf("'%s'\n", strtab_get_str(tnameref->name->sid));
-#endif
-	/* In interactive mode we are not in a class */
-	if (ctx != NULL) {
-		/* Look for type argument */
-		targ = stree_csi_find_targ(ctx, tnameref->name);
-
-		if (targ != NULL) {
-			/* Found type argument */
-#ifdef DEBUG_RUN_TRACE
-			printf("Found type argument '%s'.\n",
-			    strtab_get_str(tnameref->name->sid));
-#endif
-			titem = tdata_item_new(tic_tvref);
-			tvref = tdata_vref_new();
-			titem->u.tvref = tvref;
-			tvref->targ = targ;
-
-			*res = titem;
-			return;
-		}
-	}
-
-	/* Look for symbol */
-	sym = symbol_lookup_in_csi(prog, ctx, tnameref->name);
-	if (sym == NULL) {
-		printf("Error: Symbol '%s' not found.\n",
-		    strtab_get_str(tnameref->name->sid));
-		*res = tdata_item_new(tic_ignore);
-		return;
-	}
-
-	switch (sym->sc) {
-	case sc_csi:
-		/* Construct type item. */
-		titem = tdata_item_new(tic_tobject);
-		tobject = tdata_object_new();
-		titem->u.tobject = tobject;
-
-		tobject->static_ref = b_false;
-		tobject->csi = sym->u.csi;
-		list_init(&tobject->targs); /* XXX */
-		break;
+		list_init(&tobject->targs);
+		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
 	case sc_deleg:
 		/* Fetch stored delegate type. */
@@ -330,8 +174,228 @@
 		}
 		break;
+	case sc_enum:
+		/* Fetch stored enum type. */
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+		if (enum_d->titem == NULL) {
+			/*
+			 * Prepare a partial enum whic will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tenum);
+			tenum = tdata_enum_new();
+			titem->u.tenum = tenum;
+			tenum->enum_d = enum_d;
+		} else {
+			titem = enum_d->titem;
+		}
+		break;
 	case sc_fun:
 	case sc_var:
 	case sc_prop:
-		printf("Error: Symbol '");
+		cspan_print(taccess->member_name->cspan);
+		printf(" Error: Symbol '");
+		symbol_print_fqn(sym);
+		printf("' is not a type.\n");
+		titem = tdata_item_new(tic_ignore);
+		break;
+	}
+
+	*res = titem;
+}
+
+/** Evaluate type indexing expression.
+ *
+ * Evaluate operation per the type indexing ('[', ']') operator.
+ * A type indexing operation may have extents specified or only rank
+ * specified.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param tindex	Type indexing expression to evaluate
+ * @param res		Place to store type result
+ */
+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;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type index operation.\n");
+#endif
+	/* Evaluate base type. */
+	run_texpr(prog, ctx, tindex->base_type, &base_ti);
+
+	if (base_ti->tic == tic_ignore) {
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tarray);
+	tarray = tdata_array_new();
+	titem->u.tarray = tarray;
+
+	tarray->base_ti = base_ti;
+	tarray->rank = tindex->n_args;
+
+	/* Copy extents. */
+	list_init(&tarray->extents);
+	arg_node = list_first(&tindex->args);
+
+	while (arg_node != NULL) {
+		arg_expr = list_node_data(arg_node, stree_expr_t *);
+		list_append(&tarray->extents, arg_expr);
+		arg_node = list_next(&tindex->args, arg_node);
+	}
+
+	*res = titem;
+}
+
+/** Evaluate type literal expression.
+ *
+ * @param prog		Program
+ * @param ctx		Current CSI (context)
+ * @param tliteral	Type literal
+ * @param res		Place to store type result
+ */
+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) prog;
+	(void) ctx;
+	(void) tliteral;
+
+	switch (tliteral->tlc) {
+	case tlc_bool: tpc = tpc_bool; break;
+	case tlc_char: tpc = tpc_char; break;
+	case tlc_int: tpc = tpc_int; break;
+	case tlc_string: tpc = tpc_string; break;
+	case tlc_resource: tpc = tpc_resource; break;
+	}
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tprimitive);
+	tprimitive = tdata_primitive_new(tpc);
+	titem->u.tprimitive = tprimitive;
+
+	*res = titem;
+}
+
+static void run_tnameref(stree_program_t *prog, stree_csi_t *ctx,
+    stree_tnameref_t *tnameref, tdata_item_t **res)
+{
+	stree_symbol_t *sym;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+	stree_targ_t *targ;
+	tdata_vref_t *tvref;
+	stree_deleg_t *deleg;
+	tdata_deleg_t *tdeleg;
+	stree_enum_t *enum_d;
+	tdata_enum_t *tenum;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Evaluating type name reference.\n");
+	printf("'%s'\n", strtab_get_str(tnameref->name->sid));
+#endif
+	/* In interactive mode we are not in a class */
+	if (ctx != NULL) {
+		/* Look for type argument */
+		targ = stree_csi_find_targ(ctx, tnameref->name);
+
+		if (targ != NULL) {
+			/* Found type argument */
+#ifdef DEBUG_RUN_TRACE
+			printf("Found type argument '%s'.\n",
+			    strtab_get_str(tnameref->name->sid));
+#endif
+			titem = tdata_item_new(tic_tvref);
+			tvref = tdata_vref_new();
+			titem->u.tvref = tvref;
+			tvref->targ = targ;
+
+			*res = titem;
+			return;
+		}
+	}
+
+	/* Look for symbol */
+	sym = symbol_lookup_in_csi(prog, ctx, tnameref->name);
+	if (sym == NULL) {
+		cspan_print(tnameref->texpr->cspan);
+		printf(" Error: Symbol '%s' not found.\n",
+		    strtab_get_str(tnameref->name->sid));
+		*res = tdata_item_new(tic_ignore);
+		return;
+	}
+
+	switch (sym->sc) {
+	case sc_csi:
+		/* Construct type item. */
+		titem = tdata_item_new(tic_tobject);
+		tobject = tdata_object_new();
+		titem->u.tobject = tobject;
+
+		tobject->static_ref = b_false;
+		tobject->csi = sym->u.csi;
+		list_init(&tobject->targs);
+		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
+	case sc_deleg:
+		/* Fetch stored delegate type. */
+		deleg = symbol_to_deleg(sym);
+		assert(deleg != NULL);
+		if (deleg->titem == NULL) {
+			/*
+			 * Prepare a partial delegate which will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tdeleg);
+			tdeleg = tdata_deleg_new();
+			titem->u.tdeleg = tdeleg;
+			tdeleg->deleg = deleg;
+			tdeleg->tsig = NULL;
+
+			deleg->titem = titem;
+		} else {
+			titem = deleg->titem;
+		}
+		break;
+	case sc_enum:
+		/* Fetch stored enum type. */
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+		if (enum_d->titem == NULL) {
+			/*
+			 * Prepare a partial enum whic will be completed
+			 * later.
+			 */
+			titem = tdata_item_new(tic_tenum);
+			tenum = tdata_enum_new();
+			titem->u.tenum = tenum;
+			tenum->enum_d = enum_d;
+		} else {
+			titem = enum_d->titem;
+		}
+		break;
+	case sc_fun:
+	case sc_var:
+	case sc_prop:
+		cspan_print(tnameref->texpr->cspan);
+		printf(" Error: Symbol '");
 		symbol_print_fqn(sym);
 		printf("' is not a type.\n");
@@ -379,5 +443,6 @@
 
 	if (base_ti->tic != tic_tobject) {
-		printf("Error: Base type of generic application is not "
+		cspan_print(tapply->gtype->cspan);
+		printf(" Error: Base type of generic application is not "
 		    "a CSI.\n");
 		*res = tdata_item_new(tic_ignore);
@@ -410,5 +475,6 @@
 
 	if (farg_n != NULL || arg_n != NULL) {
-		printf("Error: Incorrect number of type arguments.\n");
+		cspan_print(tapply->texpr->cspan);
+		printf(" Error: Incorrect number of type arguments.\n");
 		*res = tdata_item_new(tic_ignore);
 		return;
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stree.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -116,4 +116,21 @@
 }
 
+/** Allocate new constructor.
+ *
+ * @return	New constructor
+ */
+stree_ctor_t *stree_ctor_new(void)
+{
+	stree_ctor_t *ctor;
+
+	ctor = calloc(1, sizeof(stree_ctor_t));
+	if (ctor == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return ctor;
+}
+
 /** Allocate new member delegate.
  *
@@ -133,4 +150,38 @@
 }
 
+/** Allocate new enum.
+ *
+ * @return	New enum
+ */
+stree_enum_t *stree_enum_new(void)
+{
+	stree_enum_t *enum_d;
+
+	enum_d = calloc(1, sizeof(stree_enum_t));
+	if (enum_d == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return enum_d;
+}
+
+/** Allocate new enum member.
+ *
+ * @return	New enum member
+ */
+stree_embr_t *stree_embr_new(void)
+{
+	stree_embr_t *embr;
+
+	embr = calloc(1, sizeof(stree_embr_t));
+	if (embr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return embr;
+}
+
 /** Allocate new member function.
  *
@@ -394,4 +445,21 @@
 }
 
+/** Allocate new @c break statement.
+ *
+ * @return	New @c break statement
+ */
+stree_break_t *stree_break_new(void)
+{
+	stree_break_t *break_s;
+
+	break_s = calloc(1, sizeof(stree_break_t));
+	if (break_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return break_s;
+}
+
 /** Allocate new @c return statement.
  *
@@ -462,4 +530,21 @@
 }
 
+/** Allocate new @c if/elif clause.
+ *
+ * @return	New @c if/elif clause
+ */
+stree_if_clause_t *stree_if_clause_new(void)
+{
+	stree_if_clause_t *if_clause;
+
+	if_clause = calloc(1, sizeof(stree_if_clause_t));
+	if (if_clause == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return if_clause;
+}
+
 /** Allocate new statement block.
  *
@@ -869,5 +954,5 @@
  * @param symbol	Symbol
  * @param sac		Symbol attribute class
- * @return		@c b_true if yes, @c b_false if no.
+ * @return		@c b_true if yes, @c b_false if no
  */
 bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac)
@@ -938,7 +1023,7 @@
 /** Search for CSI type argument of the given name.
  *
- * @param csi		CSI to look in.
- * @param ident		Identifier of the type argument.
- * @return		Type argument definition or @c NULL if not found.
+ * @param csi		CSI to look in
+ * @param ident		Identifier of the type argument
+ * @return		Type argument declaration or @c NULL if not found
  */
 stree_targ_t *stree_csi_find_targ(stree_csi_t *csi, stree_ident_t *ident)
@@ -959,2 +1044,51 @@
 	return NULL;
 }
+
+/** Search for enum member of the given name.
+ *
+ * @param enum_d	Enum to look in
+ * @param ident		Identifier of the enum member
+ * @return		Enum member declaration or @c NULL if not found
+ */
+stree_embr_t *stree_enum_find_mbr(stree_enum_t *enum_d, stree_ident_t *ident)
+{
+	list_node_t *embr_n;
+	stree_embr_t *embr;
+
+	embr_n = list_first(&enum_d->members);
+	while (embr_n != NULL) {
+		embr = list_node_data(embr_n, stree_embr_t *);
+		if (embr->name->sid == ident->sid)
+			return embr;
+
+		embr_n = list_next(&enum_d->members, embr_n);
+	}
+
+	/* No match */
+	return NULL;
+}
+
+/** Get CSI member name.
+ *
+ * @param csimbr	CSI member
+ * @return		Member name
+ */
+stree_ident_t *stree_csimbr_get_name(stree_csimbr_t *csimbr)
+{
+	stree_ident_t *mbr_name;
+
+	/* Keep compiler happy. */
+	mbr_name = NULL;
+
+	switch (csimbr->cc) {
+	case csimbr_csi: mbr_name = csimbr->u.csi->name; break;
+	case csimbr_ctor: mbr_name = csimbr->u.ctor->name; break;
+	case csimbr_deleg: mbr_name = csimbr->u.deleg->name; break;
+	case csimbr_enum: mbr_name = csimbr->u.enum_d->name; break;
+	case csimbr_fun: mbr_name = csimbr->u.fun->name; break;
+	case csimbr_var: mbr_name = csimbr->u.var->name; break;
+	case csimbr_prop: mbr_name = csimbr->u.prop->name; break;
+	}
+
+	return mbr_name;
+}
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stree.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -36,5 +36,8 @@
 stree_csi_t *stree_csi_new(csi_class_t cc);
 stree_csimbr_t *stree_csimbr_new(csimbr_class_t cc);
+stree_ctor_t *stree_ctor_new(void);
 stree_deleg_t *stree_deleg_new(void);
+stree_enum_t *stree_enum_new(void);
+stree_embr_t *stree_embr_new(void);
 stree_fun_t *stree_fun_new(void);
 stree_var_t *stree_var_new(void);
@@ -55,4 +58,5 @@
 stree_for_t *stree_for_new(void);
 stree_raise_t *stree_raise_new(void);
+stree_break_t *stree_break_new(void);
 stree_return_t *stree_return_new(void);
 stree_wef_t *stree_wef_new(void);
@@ -60,4 +64,5 @@
 
 stree_except_t *stree_except_new(void);
+stree_if_clause_t *stree_if_clause_new(void);
 stree_block_t *stree_block_new(void);
 
@@ -92,4 +97,6 @@
 bool_t stree_is_csi_derived_from_csi(stree_csi_t *a, stree_csi_t *b);
 stree_targ_t *stree_csi_find_targ(stree_csi_t *csi, stree_ident_t *ident);
+stree_embr_t *stree_enum_find_mbr(stree_enum_t *enum_d, stree_ident_t *ident);
+stree_ident_t *stree_csimbr_get_name(stree_csimbr_t *csimbr);
 
 #endif
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stree_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -43,14 +43,14 @@
 typedef struct {
 	int sid;
+	struct cspan *cspan;
 } stree_ident_t;
 
 /** Name reference */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	stree_ident_t *name;
 } stree_nameref_t;
-
-/** Reference to currently active object. */
-typedef struct {
-} stree_self_ref_t;
 
 /** Boolean literal */
@@ -88,4 +88,7 @@
 /** Literal */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	literal_class_t ltc;
 	union {
@@ -98,4 +101,10 @@
 } stree_literal_t;
 
+/** Reference to currently active object. */
+typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+} stree_self_ref_t;
+
 /** Binary operation class */
 typedef enum {
@@ -108,5 +117,7 @@
 	bo_plus,
 	bo_minus,
-	bo_mult
+	bo_mult,
+	bo_and,
+	bo_or
 } binop_class_t;
 
@@ -115,8 +126,12 @@
 	uo_plus,
 	uo_minus,
+	uo_not
 } unop_class_t;
 
 /** Binary operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Binary operation class */
 	binop_class_t bc;
@@ -128,4 +143,7 @@
 /** Unary operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Operation class */
 	unop_class_t uc;
@@ -137,10 +155,19 @@
 /** New operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Type of object to construct. */
 	struct stree_texpr *texpr;
+
+	/** Constructor arguments */
+	list_t ctor_args; /* of stree_expr_t */
 } stree_new_t;
 
 /** Member access operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Argument */
 	struct stree_expr *arg;
@@ -151,4 +178,7 @@
 /** Function call operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Function */
 	struct stree_expr *fun;
@@ -165,4 +195,7 @@
 /** Assignment */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	assign_class_t ac;
 	struct stree_expr *dest, *src;
@@ -171,4 +204,7 @@
 /** Indexing operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Base */
 	struct stree_expr *base;
@@ -180,6 +216,10 @@
 /** @c as conversion operation */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/** Expression to convert */
 	struct stree_expr *arg;
+
 	/** Destination type of conversion. */
 	struct stree_texpr *dtype;
@@ -193,4 +233,7 @@
  */
 typedef struct {
+	/** Expression backlink */
+	struct stree_expr *expr;
+
 	/* Primitive type expression */
 	struct stree_expr *arg;
@@ -217,5 +260,9 @@
 	expr_class_t ec;
 
+	/** Type of this expression or @c NULL if not typed yet */
 	struct tdata_item *titem;
+
+	/** Coordinate span */
+	struct cspan *cspan;
 
 	union {
@@ -252,4 +299,7 @@
 /** Type literal */
 typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
 	tliteral_class_t tlc;
 } stree_tliteral_t;
@@ -257,4 +307,7 @@
 /** Type name reference */
 typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
 	stree_ident_t *name;
 } stree_tnameref_t;
@@ -262,6 +315,10 @@
 /** Type member access operation */
 typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
 	/** Argument */
 	struct stree_texpr *arg;
+
 	/** Name of member being accessed. */
 	stree_ident_t *member_name;
@@ -270,4 +327,7 @@
 /** Type application operation */
 typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
 	/* Base type */
 	struct stree_texpr *gtype;
@@ -279,4 +339,7 @@
 /** Type index operation */
 typedef struct {
+	/** Type expression backlink */
+	struct stree_texpr *texpr;
+
 	/** Base type */
 	struct stree_texpr *base_type;
@@ -304,4 +367,7 @@
 typedef struct stree_texpr {
 	texpr_class_t tc;
+
+	/** Coordinate span */
+	struct cspan *cspan;
 
 	union {
@@ -337,8 +403,16 @@
 } stree_except_t;
 
+/** @c if or @c elif clause */
+typedef struct {
+	stree_expr_t *cond;
+	stree_block_t *block;
+} stree_if_clause_t;
+
 /** If statement */
 typedef struct {
-	stree_expr_t *cond;
-	stree_block_t *if_block;
+	/** If and elif clauses */
+	list_t if_clauses; /* of stree_if_clause_t */
+
+	/** Else block */
 	stree_block_t *else_block;
 } stree_if_t;
@@ -359,4 +433,8 @@
 	stree_expr_t *expr;
 } stree_raise_t;
+
+/** Break statement */
+typedef struct {
+} stree_break_t;
 
 /** Return statement */
@@ -384,4 +462,5 @@
 	st_for,
 	st_raise,
+	st_break,
 	st_return,
 	st_exps,
@@ -399,4 +478,5 @@
 		stree_for_t *for_s;
 		stree_raise_t *raise_s;
+		stree_break_t *break_s;
 		stree_return_t *return_s;
 		stree_exps_t *exp_s;
@@ -461,4 +541,22 @@
 } stree_proc_t;
 
+/** Constructor declaration */
+typedef struct stree_ctor {
+	/** Constructor 'name'. Points to the @c new keyword. */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** Signature (arguments, return type is always none) */
+	stree_fun_sig_t *sig;
+
+	/** Constructor implementation */
+	stree_proc_t *proc;
+
+	/** Type item describing the constructor */
+	struct tdata_item *titem;
+} stree_ctor_t;
+
 /** Delegate declaration */
 typedef struct stree_deleg {
@@ -476,4 +574,28 @@
 } stree_deleg_t;
 
+/** Enum member */
+typedef struct stree_embr {
+	/** Enum containing this declaration */
+	struct stree_enum *outer_enum;
+
+	/** Enum member name */
+	stree_ident_t *name;
+} stree_embr_t;
+
+/** Enum declaration */
+typedef struct stree_enum {
+	/** Enum name */
+	stree_ident_t *name;
+
+	/** Symbol */
+	struct stree_symbol *symbol;
+
+	/** List of enum members */
+	list_t members; /* of stree_embr_t */
+
+	/** Type item describing the enum */
+	struct tdata_item *titem;
+} stree_enum_t;
+
 /** Member function declaration */
 typedef struct stree_fun {
@@ -521,11 +643,13 @@
 /**
  * Fake identifiers used with symbols that do not really have one.
- * (Mostly for error messages.)
  */
+#define CTOR_IDENT "$ctor"
 #define INDEXER_IDENT "$indexer"
 
 typedef enum {
 	csimbr_csi,
+	csimbr_ctor,
 	csimbr_deleg,
+	csimbr_enum,
 	csimbr_fun,
 	csimbr_var,
@@ -539,5 +663,7 @@
 	union {
 		struct stree_csi *csi;
+		stree_ctor_t *ctor;
 		stree_deleg_t *deleg;
+		stree_enum_t *enum_d;
 		stree_fun_t *fun;
 		stree_var_t *var;
@@ -587,5 +713,7 @@
 typedef enum {
 	/* Class, struct or interface declaration */
-	mc_csi
+	mc_csi,
+	/* Enum declaration */
+	mc_enum
 } modm_class_t;
 
@@ -595,4 +723,5 @@
 	union {
 		stree_csi_t *csi;
+		stree_enum_t *enum_d;
 	} u;
 } stree_modm_t;
@@ -618,6 +747,10 @@
 	/** CSI (class, struct or interface) */
 	sc_csi,
+	/** Constructor */
+	sc_ctor,
 	/** Member delegate */
 	sc_deleg,
+	/** Enum */
+	sc_enum,
 	/** Member function */
 	sc_fun,
@@ -638,5 +771,7 @@
 	union {
 		struct stree_csi *csi;
+		stree_ctor_t *ctor;
 		stree_deleg_t *deleg;
+		stree_enum_t *enum_d;
 		stree_fun_t *fun;
 		stree_var_t *var;
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stype.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -38,4 +38,5 @@
 #include <stdlib.h>
 #include <assert.h>
+#include "cspan.h"
 #include "debug.h"
 #include "intmap.h"
@@ -52,4 +53,6 @@
 
 static void stype_csi(stype_t *stype, stree_csi_t *csi);
+static void stype_ctor(stype_t *stype, stree_ctor_t *ctor);
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor);
 static void stype_fun(stype_t *stype, stree_fun_t *fun);
 static void stype_var(stype_t *stype, stree_var_t *var);
@@ -66,4 +69,5 @@
 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_break(stype_t *stype, stree_break_t *break_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, bool_t want_value);
@@ -80,9 +84,11 @@
 static stree_expr_t *stype_convert_tdeleg(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest);
 static stree_expr_t *stype_convert_tfun_tdeleg(stype_t *stype,
     stree_expr_t *expr, tdata_item_t *dest);
 static stree_expr_t *stype_convert_tvref(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
-static void stype_convert_failure(stype_t *stype, tdata_item_t *src,
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
 
@@ -112,7 +118,13 @@
 	while (mbr_n != NULL) {
 		mbr = list_node_data(mbr_n, stree_modm_t *);
-		assert(mbr->mc == mc_csi);
-
-		stype_csi(stype, mbr->u.csi);
+
+		switch (mbr->mc) {
+		case mc_csi:
+			stype_csi(stype, mbr->u.csi);
+			break;
+		case mc_enum:
+			stype_enum(stype, mbr->u.enum_d);
+			break;
+		}
 
 		mbr_n = list_next(&module->members, mbr_n);
@@ -145,5 +157,7 @@
 		switch (csimbr->cc) {
 		case csimbr_csi: stype_csi(stype, csimbr->u.csi); break;
+		case csimbr_ctor: stype_ctor(stype, csimbr->u.ctor); break;
 		case csimbr_deleg: stype_deleg(stype, csimbr->u.deleg); break;
+		case csimbr_enum: stype_enum(stype, csimbr->u.enum_d); break;
 		case csimbr_fun: stype_fun(stype, csimbr->u.fun); break;
 		case csimbr_var: stype_var(stype, csimbr->u.var); break;
@@ -155,4 +169,79 @@
 
 	stype->current_csi = prev_ctx;
+}
+
+/** Type a constructor.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+static void stype_ctor(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("'.\n");
+#endif
+	if (ctor->titem == NULL)
+		stype_ctor_header(stype, ctor);
+
+	stype_ctor_body(stype, ctor);
+}
+
+/** Type constructor header.
+ *
+ * @param stype		Static typing object.
+ * @param ctor		Constructor to type.
+ */
+void stype_ctor_header(stype_t *stype, stree_ctor_t *ctor)
+{
+	stree_symbol_t *ctor_sym;
+	tdata_item_t *ctor_ti;
+	tdata_fun_t *tfun;
+	tdata_fun_sig_t *tsig;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' header.\n");
+#endif
+	if (ctor->titem != NULL)
+		return; /* Constructor header has already been typed. */
+
+	ctor_sym = ctor_to_symbol(ctor);
+
+	/* Type function signature. */
+	stype_fun_sig(stype, ctor_sym->outer_csi, ctor->sig, &tsig);
+
+	ctor_ti = tdata_item_new(tic_tfun);
+	tfun = tdata_fun_new();
+	ctor_ti->u.tfun = tfun;
+	tfun->tsig = tsig;
+
+	ctor->titem = ctor_ti;
+}
+
+/** Type constructor body.
+ *
+ * @param stype		Static typing object
+ * @param ctor		Constructor
+ */
+static void stype_ctor_body(stype_t *stype, stree_ctor_t *ctor)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type constructor '");
+	symbol_print_fqn(ctor_to_symbol(ctor));
+	printf("' body.\n");
+#endif
+	assert(stype->proc_vr == NULL);
+
+	stype->proc_vr = stype_proc_vr_new();
+	stype->proc_vr->proc = ctor->proc;
+	list_init(&stype->proc_vr->block_vr);
+
+	stype_block(stype, ctor->proc->body);
+
+	free(stype->proc_vr);
+	stype->proc_vr = NULL;
 }
 
@@ -197,4 +286,33 @@
 }
 
+/** Type enum.
+ *
+ * @param stype		Static typing object
+ * @param enum_d	Enum to type
+ */
+void stype_enum(stype_t *stype, stree_enum_t *enum_d)
+{
+	tdata_item_t *titem;
+	tdata_enum_t *tenum;
+
+	(void) stype;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type enum '");
+	symbol_print_fqn(enum_to_symbol(enum_d));
+	printf("'.\n");
+#endif
+	if (enum_d->titem == NULL) {
+		titem = tdata_item_new(tic_tenum);
+		tenum = tdata_enum_new();
+		titem->u.tenum = tenum;
+		tenum->enum_d = enum_d;
+
+		enum_d->titem = titem;
+	} else {
+		titem = enum_d->titem;
+	}
+}
+
 /** Type function.
  *
@@ -457,4 +575,5 @@
 	case st_for: stype_for(stype, stat->u.for_s); break;
 	case st_raise: stype_raise(stype, stat->u.raise_s); break;
+	case st_break: stype_break(stype, stat->u.break_s); break;
 	case st_return: stype_return(stype, stat->u.return_s); break;
 	case st_exps: stype_exps(stype, stat->u.exp_s, want_value); break;
@@ -506,17 +625,31 @@
 {
 	stree_expr_t *ccond;
+	list_node_t *ifc_node;
+	stree_if_clause_t *ifc;
 
 #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);
+	ifc_node = list_first(&if_s->if_clauses);
+
+	/* Walk through all if/elif clauses. */
+
+	while (ifc_node != NULL) {
+		/* Get if/elif clause */
+		ifc = list_node_data(ifc_node, stree_if_clause_t *);
+
+		/* Convert condition to boolean type. */
+		stype_expr(stype, ifc->cond);
+		ccond = stype_convert(stype, ifc->cond,
+		    stype_boolean_titem(stype));
+
+		/* Patch code with augmented expression. */
+		ifc->cond = ccond;
+
+		/* Type the @c if/elif block */
+		stype_block(stype, ifc->block);
+
+		ifc_node = list_next(&if_s->if_clauses, ifc_node);
+	}
 
 	/* Type the @c else block */
@@ -545,6 +678,11 @@
 	while_s->cond = ccond;
 
+	/* While is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
 	/* Type the body of the loop */
 	stype_block(stype, while_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
 }
 
@@ -559,5 +697,10 @@
 	printf("Type 'for' statement.\n");
 #endif
+	/* For is a breakable statement. Increment counter. */
+	stype->proc_vr->bstat_cnt += 1;
+
 	stype_block(stype, for_s->body);
+
+	stype->proc_vr->bstat_cnt -= 1;
 }
 
@@ -573,4 +716,19 @@
 #endif
 	stype_expr(stype, raise_s->expr);
+}
+
+/** Type @c break statement */
+static void stype_break(stype_t *stype, stree_break_t *break_s)
+{
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'break' statement.\n");
+#endif
+	(void) break_s;
+
+	/* Check whether there is an active statement to break from. */
+	if (stype->proc_vr->bstat_cnt == 0) {
+		printf("Error: Break statement outside of while or for.\n");
+		stype_note_error(stype);
+	}
 }
 
@@ -588,5 +746,6 @@
 	printf("Type 'return' statement.\n");
 #endif
-	stype_expr(stype, return_s->expr);
+	if (return_s->expr != NULL)
+		stype_expr(stype, return_s->expr);
 
 	/* Determine the type we need to return. */
@@ -599,6 +758,22 @@
 
 		/* XXX Memoize to avoid recomputing. */
-		run_texpr(stype->program, outer_sym->outer_csi,
-		    fun->sig->rtype, &dtype);
+		if (fun->sig->rtype != NULL) {
+			run_texpr(stype->program, outer_sym->outer_csi,
+			    fun->sig->rtype, &dtype);
+
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "function returning value.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			dtype = NULL;
+
+			if (return_s->expr != NULL) {
+				printf("Error: Return with a value in "
+				    "value-less function.\n");
+				stype_note_error(stype);
+			}
+		}
 		break;
 	case sc_prop:
@@ -606,8 +781,16 @@
 		assert(prop != NULL);
 
-		if (stype->proc_vr->proc != prop->getter) {
-			printf("Error: Return statement in "
-			    "setter.\n");
-			stype_note_error(stype);
+		if (stype->proc_vr->proc == prop->getter) {
+			if (return_s->expr == NULL) {
+				printf("Error: Return without a value in "
+				    "getter.\n");
+				stype_note_error(stype);
+			}
+		} else {
+			if (return_s->expr == NULL) {
+				printf("Error: Return with a value in "
+				    "setter.\n");
+				stype_note_error(stype);
+			}
 		}
 
@@ -620,9 +803,11 @@
 	}
 
-	/* Convert to the return type. */
-	cexpr = stype_convert(stype, return_s->expr, dtype);
-
-	/* Patch code with the augmented expression. */
-	return_s->expr = cexpr;
+	if (dtype != NULL && return_s->expr != NULL) {
+		/* Convert to the return type. */
+		cexpr = stype_convert(stype, return_s->expr, dtype);
+
+		/* Patch code with the augmented expression. */
+		return_s->expr = cexpr;
+	}
 }
 
@@ -714,5 +899,6 @@
 
 	if (src == NULL) {
-		printf("Error: Conversion source is not valid.\n");
+		cspan_print(expr->cspan);
+		printf(" Error: Conversion source is not valid.\n");
 		stype_note_error(stype);
 		return expr;
@@ -738,6 +924,13 @@
 	}
 
+	if (src->tic == tic_tebase) {
+		stype_convert_failure(stype, expr, dest);
+		printf("Invalid use of reference to enum type in "
+		    "expression.\n");
+		return expr;
+	}
+
 	if (src->tic != dest->tic) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -756,4 +949,10 @@
 		expr = stype_convert_tdeleg(stype, expr, dest);
 		break;
+	case tic_tebase:
+		/* Conversion destination should never be enum-base */
+		assert(b_false);
+	case tic_tenum:
+		expr = stype_convert_tenum(stype, expr, dest);
+		break;
 	case tic_tfun:
 		assert(b_false);
@@ -788,5 +987,5 @@
 	/* Check if both have the same tprimitive class. */
 	if (src->u.tprimitive->tpc != dest->u.tprimitive->tpc)
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 
 	return expr;
@@ -795,5 +994,6 @@
 /** Convert expression of primitive type to object type.
  *
- * This function implements autoboxing. It modified the code.
+ * This function implements autoboxing. It modifies the code by inserting
+ * the boxing operation.
  *
  * @param stype		Static typing object
@@ -828,5 +1028,5 @@
 	case tpc_string: bp_sym = bi->boxed_string; break;
 	case tpc_resource:
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -834,5 +1034,5 @@
 	/* Target type must be boxed @a src or Object */
 	if (csi_sym != bp_sym && csi_sym != bi->gf_class)
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 
 	/* Patch the code to box the primitive value */
@@ -841,4 +1041,5 @@
 	bexpr = stree_expr_new(ec_box);
 	bexpr->u.box = box;
+	bexpr->titem = dest;
 
 	/* No action needed to optionally convert boxed type to Object */
@@ -901,5 +1102,5 @@
 		} else {
 			/* No match */
-			stype_convert_failure(stype, src, dest);
+			stype_convert_failure(stype, expr, dest);
 			return expr;
 		}
@@ -916,5 +1117,5 @@
 		if (tdata_item_equal(carg, darg) != b_true) {
 			/* Diferent argument type */
-			stype_convert_failure(stype, src, dest);
+			stype_convert_failure(stype, expr, dest);
 			printf("Different argument type '");
 			tdata_item_print(carg);
@@ -931,5 +1132,5 @@
 	if (ca_n != NULL || da_n != NULL) {
 		/* Diferent number of arguments */
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		printf("Different number of arguments.\n");
 		return expr;
@@ -959,5 +1160,5 @@
 	/* Compare rank and base type. */
 	if (src->u.tarray->rank != dest->u.tarray->rank) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -966,5 +1167,5 @@
 	if (tdata_item_equal(src->u.tarray->base_ti,
 	    dest->u.tarray->base_ti) != b_true) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 	}
 
@@ -1004,5 +1205,40 @@
 	/* Both must be the same delegate. */
 	if (sdeleg->deleg != ddeleg->deleg) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
+		return expr;
+	}
+
+	return expr;
+}
+
+/** Convert expression of enum type to enum type.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @param dest		Destination type
+ */
+static stree_expr_t *stype_convert_tenum(stype_t *stype, stree_expr_t *expr,
+    tdata_item_t *dest)
+{
+	tdata_item_t *src;
+	tdata_enum_t *senum, *denum;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Convert enum type.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tenum);
+	assert(dest->tic == tic_tenum);
+
+	senum = src->u.tenum;
+	denum = dest->u.tenum;
+
+	/*
+	 * XXX How should enum types interact with generics?
+	 */
+
+	/* Both must be of the same enum type (with the same declaration). */
+	if (senum->enum_d != denum->enum_d) {
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1043,5 +1279,5 @@
 
 	if (!stype_fun_sig_equal(stype, ssig, dsig)) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1075,5 +1311,5 @@
 	/* Currently only allow if both types are the same. */
 	if (src->u.tvref->targ != dest->u.tvref->targ) {
-		stype_convert_failure(stype, src, dest);
+		stype_convert_failure(stype, expr, dest);
 		return expr;
 	}
@@ -1085,12 +1321,13 @@
  *
  * @param stype		Static typing object
- * @param src		Original type
+ * @param expr		Original expression
  * @param dest		Destination type
  */
-static void stype_convert_failure(stype_t *stype, tdata_item_t *src,
+static void stype_convert_failure(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest)
 {
-	printf("Error: Cannot convert ");
-	tdata_item_print(src);
+	cspan_print(expr->cspan);
+	printf(" Error: Cannot convert ");
+	tdata_item_print(expr->titem);
 	printf(" to ");
 	tdata_item_print(dest);
@@ -1099,4 +1336,66 @@
 	stype_note_error(stype);
 }
+
+/** Box value.
+ *
+ * This function implements implicit boxing. It modifies the code by inserting
+ * the boxing operation.
+ *
+ * @param stype		Static typing object
+ * @param expr		Expression
+ * @return		Modified expression.
+ */
+stree_expr_t *stype_box_expr(stype_t *stype, stree_expr_t *expr)
+{
+	tdata_item_t *src;
+	builtin_t *bi;
+	stree_symbol_t *bp_sym;
+	stree_box_t *box;
+	stree_expr_t *bexpr;
+	tdata_object_t *tobject;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Boxing.\n");
+#endif
+	src = expr->titem;
+	assert(src->tic == tic_tprimitive);
+
+	bi = stype->program->builtin;
+
+	/* Make compiler happy. */
+	bp_sym = NULL;
+
+	switch (src->u.tprimitive->tpc) {
+	case tpc_bool: bp_sym = bi->boxed_bool; break;
+	case tpc_char: bp_sym = bi->boxed_char; break;
+	case tpc_int: bp_sym = bi->boxed_int; break;
+	case tpc_nil: assert(b_false);
+	case tpc_string: bp_sym = bi->boxed_string; break;
+	case tpc_resource:
+		cspan_print(expr->cspan);
+		printf(" Error: Cannot use ");
+		tdata_item_print(expr->titem);
+		printf(" as an object.\n");
+
+		stype_note_error(stype);
+		return expr;
+	}
+
+	/* Patch the code to box the primitive value */
+	box = stree_box_new();
+	box->arg = expr;
+	bexpr = stree_expr_new(ec_box);
+	bexpr->u.box = box;
+	bexpr->titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	bexpr->titem->u.tobject = tobject;
+
+	tobject->csi = symbol_to_csi(bp_sym);
+	assert(tobject->csi != NULL);
+
+	return bexpr;
+}
+
+
 
 /** Determine if two type signatures are equal.
@@ -1296,4 +1595,5 @@
 
 	stree_symbol_t *outer_sym;
+	stree_ctor_t *ctor;
 	stree_fun_t *fun;
 	stree_prop_t *prop;
@@ -1314,5 +1614,15 @@
 #endif
 
+	/* Make compiler happy. */
+	args = NULL;
+	varg = NULL;
+
 	switch (outer_sym->sc) {
+	case sc_ctor:
+		ctor = symbol_to_ctor(outer_sym);
+		assert(ctor != NULL);
+		args = &ctor->sig->args;
+		varg = ctor->sig->varg;
+		break;
 	case sc_fun:
 		fun = symbol_to_fun(outer_sym);
@@ -1331,5 +1641,8 @@
 			setter_arg = prop->setter_arg;
 		break;
-	default:
+	case sc_csi:
+	case sc_deleg:
+	case sc_enum:
+	case sc_var:
 		assert(b_false);
 	}
Index: uspace/app/sbi/src/stype.h
===================================================================
--- uspace/app/sbi/src/stype.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stype.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -33,5 +33,7 @@
 
 void stype_module(stype_t *stype, stree_module_t *module);
+void stype_ctor_header(stype_t *stype, stree_ctor_t *ctor);
 void stype_deleg(stype_t *stype, stree_deleg_t *deleg);
+void stype_enum(stype_t *stype, stree_enum_t *enum_d);
 void stype_fun_header(stype_t *stype, stree_fun_t *fun);
 void stype_stat(stype_t *stype, stree_stat_t *stat, bool_t want_value);
@@ -42,4 +44,5 @@
 stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
     tdata_item_t *dest);
+stree_expr_t *stype_box_expr(stype_t *stype, stree_expr_t *expr);
 
 tdata_fun_sig_t *stype_deleg_get_sig(stype_t *stype, tdata_deleg_t *tdeleg);
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stype_expr.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -46,4 +46,5 @@
 #include <stdlib.h>
 #include <assert.h>
+#include "cspan.h"
 #include "debug.h"
 #include "list.h"
@@ -85,4 +86,8 @@
 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_binop_tenum(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem);
+static void stype_binop_tvref(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,
@@ -92,4 +97,6 @@
 static void stype_new(stype_t *stype, stree_new_t *new,
     tdata_item_t **rtitem);
+static void stype_new_object_args(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t *obj_ti);
 
 static void stype_access(stype_t *stype, stree_access_t *access,
@@ -101,7 +108,11 @@
 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_tebase(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_call_args(stype_t *stype, cspan_t *cspan, list_t *farg_tis,
+    tdata_item_t *fvarg_ti, list_t *args);
 
 static void stype_index(stype_t *stype, stree_index_t *index,
@@ -133,5 +144,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Type expression.\n");
+	cspan_print(expr->cspan);
+	printf(" Type expression.\n");
 #endif
 	/* Silence warning. */
@@ -156,5 +168,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Expression type is '");
+	cspan_print(expr->cspan);
+	printf(" Expression type is '");
 	tdata_item_print(et);
 	printf("'.\n");
@@ -178,8 +191,11 @@
 	stree_csi_t *csi;
 	stree_deleg_t *deleg;
+	stree_enum_t *enum_d;
+	tdata_ebase_t *tebase;
 	stree_fun_t *fun;
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of name reference '%s'.\n",
+	cspan_print(nameref->expr->cspan);
+	printf(" Evaluate type of name reference '%s'.\n",
 	    strtab_get_str(nameref->name->sid));
 #endif
@@ -226,10 +242,12 @@
 		/* Not found. */
 		if (stype->current_csi != NULL) {
-			printf("Error: Symbol '%s' not found in '",
+			cspan_print(nameref->expr->cspan);
+			printf(" Error: Symbol '%s' not found in '",
 			    strtab_get_str(nameref->name->sid));
 			symbol_print_fqn(csi_to_symbol(stype->current_csi));
 			printf("'.\n");
 		} else {
-			printf("Error: Symbol '%s' not found.\n",
+			cspan_print(nameref->expr->cspan);
+			printf(" Error: Symbol '%s' not found.\n",
 			    strtab_get_str(nameref->name->sid));
 		}
@@ -260,6 +278,8 @@
 		tobject->csi = csi;
 		break;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
 	case sc_deleg:
-		printf("referenced name is deleg\n");
 		deleg = symbol_to_deleg(sym);
 		assert(deleg != NULL);
@@ -267,4 +287,15 @@
 		stype_deleg(stype, deleg);
 		titem = deleg->titem;
+		break;
+	case sc_enum:
+		enum_d = symbol_to_enum(sym);
+		assert(enum_d != NULL);
+
+		titem = tdata_item_new(tic_tebase);
+		tebase = tdata_ebase_new();
+		titem->u.tebase = tebase;
+
+		/* This is an enum base reference. */
+		tebase->enum_d = enum_d;
 		break;
 	case sc_fun:
@@ -294,5 +325,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of literal.\n");
+	cspan_print(literal->expr->cspan);
+	printf(" Evaluate type of literal.\n");
 #endif
 	(void) stype;
@@ -322,11 +354,30 @@
     tdata_item_t **rtitem)
 {
+	stree_csi_t *cur_csi;
+	tdata_item_t *titem;
+	tdata_object_t *tobject;
+
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of self reference.\n");
+	cspan_print(self_ref->expr->cspan);
+	printf(" Evaluate type of self reference.\n");
 #endif
 	(void) stype;
 	(void) self_ref;
 
-	*rtitem = NULL;
+	cur_csi = stype->proc_vr->proc->outer_symbol->outer_csi;
+
+	/* No global symbols should have procedures. */
+	assert(cur_csi != NULL);
+
+	/* Construct type item. */
+	titem = tdata_item_new(tic_tobject);
+	tobject = tdata_object_new();
+	titem->u.tobject = tobject;
+
+	tobject->static_ref = b_false;
+	tobject->csi = cur_csi;
+	list_init(&tobject->targs);
+
+	*rtitem = titem;
 }
 
@@ -344,5 +395,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of binary operation.\n");
+	cspan_print(binop->expr->cspan);
+	printf(" Evaluate type of binary operation.\n");
 #endif
 	stype_expr(stype, binop->arg1);
@@ -352,6 +404,15 @@
 	titem2 = binop->arg2->titem;
 
-	if (titem1 == NULL || titem2 == NULL) {
-		printf("Error: Binary operand has no value.\n");
+	if (titem1 == NULL) {
+		cspan_print(binop->arg1->cspan);
+		printf(" Error: Binary operand has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if (titem2 == NULL) {
+		cspan_print(binop->arg2->cspan);
+		printf(" Error: Binary operand has no value.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
@@ -366,5 +427,6 @@
 	equal = tdata_item_equal(titem1, titem2);
 	if (equal != b_true) {
-		printf("Error: Binary operation arguments "
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation arguments "
 		    "have different types ('");
 		tdata_item_print(titem1);
@@ -384,6 +446,13 @@
 		stype_binop_tobject(stype, binop, titem1, titem2, rtitem);
 		break;
+	case tic_tenum:
+		stype_binop_tenum(stype, binop, titem1, titem2, rtitem);
+		break;
+	case tic_tvref:
+		stype_binop_tvref(stype, binop, titem1, titem2, rtitem);
+		break;
 	default:
-		printf("Error: Binary operation on value which is not of a "
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation on value which is not of a "
 		    "supported type (found '");
 		tdata_item_print(titem1);
@@ -458,9 +527,15 @@
 	case bo_mult:
 		/* Arithmetic -> error */
-		printf("Error: Binary operation (%d) on booleans.\n",
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on booleans.\n",
 		    binop->bc);
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
 		return;
+	case bo_and:
+	case bo_or:
+		/* Boolean -> boolean type */
+		rtpc = tpc_bool;
+		break;
 	}
 
@@ -498,6 +573,9 @@
 	case bo_minus:
 	case bo_mult:
-		/* Arithmetic -> error */
-		printf("Error: Binary operation (%d) on characters.\n",
+	case bo_and:
+	case bo_or:
+		/* Arithmetic, boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on characters.\n",
 		    binop->bc);
 		stype_note_error(stype);
@@ -542,4 +620,13 @@
 		rtpc = tpc_int;
 		break;
+	case bo_and:
+	case bo_or:
+		/* Boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on integers.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		rtpc = tpc_char;
+		break;
 	}
 
@@ -561,5 +648,6 @@
 	(void) binop;
 
-	printf("Unimplemented; Binary operation on nil.\n");
+	cspan_print(binop->expr->cspan);
+	printf(" Unimplemented: Binary operation on nil.\n");
 	stype_note_error(stype);
 	*rtitem = stype_recovery_titem(stype);
@@ -578,13 +666,32 @@
 	tdata_item_t *res_ti;
 
-	if (binop->bc != bo_plus) {
-		printf("Unimplemented: Binary operation(%d) "
-		    "on strings.\n", binop->bc);
-		stype_note_error(stype);
-		*rtitem = stype_recovery_titem(stype);
-		return;
-	}
-
-	rtpc = tpc_string;
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		rtpc = tpc_bool;
+		break;
+	case bo_plus:
+		/* Concatenation -> string type */
+		rtpc = tpc_string;
+		break;
+
+	case bo_lt:
+	case bo_gt:
+	case bo_lt_equal:
+	case bo_gt_equal:
+
+	case bo_minus:
+	case bo_mult:
+	case bo_and:
+	case bo_or:
+		/* Ordering, arithmetic, boolean -> error */
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on strings.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		rtpc = tpc_char;
+		break;
+	}
 
 	res_ti = tdata_item_new(tic_tprimitive);
@@ -608,5 +715,6 @@
 	(void) binop;
 
-	printf("Error: Cannot apply operator to resource type.\n");
+	cspan_print(binop->expr->cspan);
+	printf(" Error: Cannot apply operator to resource type.\n");
 	stype_note_error(stype);
 	rtpc = tpc_resource;
@@ -645,5 +753,6 @@
 		break;
 	default:
-		printf("Error: Binary operation (%d) on objects.\n",
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on objects.\n",
 		    binop->bc);
 		stype_note_error(stype);
@@ -655,4 +764,73 @@
 }
 
+/** Type a binary operation with arguments of an enum type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_tenum(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	assert(ta->tic == tic_tenum);
+	assert(tb->tic == tic_tenum);
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		res_ti = stype_boolean_titem(stype);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on values of enum "
+		    "type.\n", binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	*rtitem = res_ti;
+}
+
+/** Type a binary operation with arguments of a variable type.
+ *
+ * @param stype		Static typing object
+ * @param binop		Binary operation
+ * @param ta		Type of first argument
+ * @param tb		Type of second argument
+ * @param rtitem	Place to store result type
+ */
+static void stype_binop_tvref(stype_t *stype, stree_binop_t *binop,
+    tdata_item_t *ta, tdata_item_t *tb, tdata_item_t **rtitem)
+{
+	tdata_item_t *res_ti;
+
+	assert(ta->tic == tic_tvref || (ta->tic == tic_tprimitive &&
+	    ta->u.tprimitive->tpc == tpc_nil));
+	assert(tb->tic == tic_tvref || (tb->tic == tic_tprimitive &&
+	    tb->u.tprimitive->tpc == tpc_nil));
+
+	switch (binop->bc) {
+	case bo_equal:
+	case bo_notequal:
+		/* Comparison -> boolean type */
+		res_ti = stype_boolean_titem(stype);
+		break;
+	default:
+		cspan_print(binop->expr->cspan);
+		printf(" Error: Binary operation (%d) on variable types.\n",
+		    binop->bc);
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	*rtitem = res_ti;
+}
 
 /** Type a unary operation.
@@ -668,5 +846,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of unary operation.\n");
+	cspan_print(unop->expr->cspan);
+	printf(" Evaluate type of unary operation.\n");
 #endif
 	stype_expr(stype, unop->arg);
@@ -684,5 +863,6 @@
 		break;
 	default:
-		printf("Error: Unary operation on value which is not of a "
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Unary operation on value which is not of a "
 		    "supported type (found '");
 		tdata_item_print(titem);
@@ -720,5 +900,6 @@
 		break;
 	default:
-		printf("Error: Unary operator applied on unsupported "
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Unary operator applied on unsupported "
 		    "primitive type %d.\n", ta->u.tprimitive->tpc);
 		stype_note_error(stype);
@@ -743,4 +924,5 @@
 {
 #ifdef DEBUG_TYPE_TRACE
+	cspan_print(new_op->expr->cspan);
 	printf("Evaluate type of 'new' operation.\n");
 #endif
@@ -754,5 +936,59 @@
 		/* An error occured when evaluating the type expression. */
 		stype_note_error(stype);
-	}
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	if ((*rtitem)->tic == tic_tobject)
+		stype_new_object_args(stype, new_op, *rtitem);
+}
+
+/** Type a new object operation arguments.
+ *
+ * @param stype		Static typing object
+ * @param new_op	@c new operation
+ */
+static void stype_new_object_args(stype_t *stype, stree_new_t *new_op,
+    tdata_item_t *obj_ti)
+{
+	stree_csi_t *csi;
+	stree_ctor_t *ctor;
+	stree_symbol_t *ctor_sym;
+	stree_ident_t *ctor_ident;
+	tdata_fun_sig_t *tsig;
+
+	assert(obj_ti->tic == tic_tobject);
+	csi = obj_ti->u.tobject->csi;
+	ctor_ident = stree_ident_new();
+	ctor_ident->sid = strtab_get_sid(CTOR_IDENT);
+
+	/* Find constructor. */
+	ctor_sym = symbol_search_csi_no_base(stype->program, csi,
+	    ctor_ident);
+
+	if (ctor_sym == NULL && !list_is_empty(&new_op->ctor_args)) {
+		cspan_print(new_op->expr->cspan);
+		printf(" Error: Passing arguments to 'new' but no "
+		    "constructor found.\n");
+		stype_note_error(stype);
+		return;
+	}
+
+	if (ctor_sym == NULL)
+		return;
+
+	ctor = symbol_to_ctor(ctor_sym);
+	assert(ctor != NULL);
+
+	/* Type constructor header if it has not been typed yet. */
+	stype_ctor_header(stype, ctor);
+	if (ctor->titem->tic == tic_ignore)
+		return;
+
+	assert(ctor->titem->tic == tic_tfun);
+	tsig = ctor->titem->u.tfun->tsig;
+
+	stype_call_args(stype, new_op->expr->cspan, &tsig->arg_ti,
+	    tsig->varg_ti, &new_op->ctor_args);
 }
 
@@ -769,5 +1005,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of access operation.\n");
+	cspan_print(access->expr->cspan);
+	printf(" Evaluate type of access operation.\n");
 #endif
 	stype_expr(stype, access->arg);
@@ -775,5 +1012,6 @@
 
 	if (arg_ti == NULL) {
-		printf("Error: Argument of access has no value.\n");
+		cspan_print(access->arg->cspan);
+		printf(" Error: Argument of access operation has no value.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
@@ -792,10 +1030,22 @@
 		break;
 	case tic_tdeleg:
-		printf("Error: Using '.' operator on a function.\n");
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on a delegate.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tebase:
+		stype_access_tebase(stype, access, arg_ti, rtitem);
+		break;
+	case tic_tenum:
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on expression of enum "
+		    "type.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
 		break;
 	case tic_tfun:
-		printf("Error: Using '.' operator on a delegate.\n");
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on a function.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
@@ -803,5 +1053,6 @@
 	case tic_tvref:
 		/* Cannot allow this without some constraint. */
-		printf("Error: Using '.' operator on generic data.\n");
+		cspan_print(access->arg->cspan);
+		printf(" Error: Using '.' operator on generic data.\n");
 		*rtitem = stype_recovery_titem(stype);
 		break;
@@ -822,13 +1073,15 @@
     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");
-	stype_note_error(stype);
-	*rtitem = stype_recovery_titem(stype);
+	(void) arg_ti;
+
+	/* Box the value. */
+	access->arg = stype_box_expr(stype, access->arg);
+	if (access->arg->titem->tic == tic_ignore) {
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+	/* Access the boxed object. */
+	stype_access_tobject(stype, access, access->arg->titem, rtitem);
 }
 
@@ -845,4 +1098,5 @@
 	stree_symbol_t *member_sym;
 	stree_var_t *var;
+	stree_enum_t *enum_d;
 	stree_fun_t *fun;
 	stree_prop_t *prop;
@@ -863,5 +1117,6 @@
 	if (member_sym == NULL) {
 		/* No such member found. */
-		printf("Error: CSI '");
+		cspan_print(access->member_name->cspan);
+		printf(" Error: CSI '");
 		symbol_print_fqn(csi_to_symbol(tobject->csi));
 		printf("' has no member named '%s'.\n",
@@ -879,15 +1134,27 @@
 	switch (member_sym->sc) {
 	case sc_csi:
-		printf("Error: Accessing object member which is nested "
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Accessing object member which is nested "
 		    "CSI.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
 		return;
+	case sc_ctor:
+		/* It is not possible to reference a constructor explicitly. */
+		assert(b_false);
 	case sc_deleg:
-		printf("Error: Accessing object member which is a "
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Accessing object member which is a "
 		    "delegate.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
 		return;
+	case sc_enum:
+		enum_d = symbol_to_enum(member_sym);
+		assert(enum_d != NULL);
+		/* Type enum if it has not been typed yet. */
+		stype_enum(stype, enum_d);
+		mtitem = enum_d->titem;
+		break;
 	case sc_fun:
 		fun = symbol_to_fun(member_sym);
@@ -937,5 +1204,6 @@
 	(void) rtitem;
 
-	printf("Error: Unimplemented: Accessing array type '");
+	cspan_print(access->arg->cspan);
+	printf(" Error: Unimplemented: Accessing array type '");
 	tdata_item_print(arg_ti);
 	printf("'.\n");
@@ -944,4 +1212,54 @@
 }
 
+/** Type an enum access operation.
+ *
+ * @param stype		Static typing object
+ * @param access	Member access operation
+ * @param arg_ti	Base type
+ * @param rtitem	Place to store result type
+*/
+static void stype_access_tebase(stype_t *stype, stree_access_t *access,
+    tdata_item_t *arg_ti, tdata_item_t **rtitem)
+{
+	tdata_ebase_t *tebase;
+	tdata_enum_t *tenum;
+	tdata_item_t *mtitem;
+	stree_embr_t *embr;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type an ebase access operation.\n");
+#endif
+	assert(arg_ti->tic == tic_tebase);
+	tebase = arg_ti->u.tebase;
+
+	/* Look for a member with the specified name. */
+	embr = stree_enum_find_mbr(tebase->enum_d, access->member_name);
+
+	if (embr == NULL) {
+		/* No such member found. */
+		cspan_print(access->member_name->cspan);
+		printf(" Error: Enum type '");
+		symbol_print_fqn(enum_to_symbol(tebase->enum_d));
+		printf("' has no member named '%s'.\n",
+		    strtab_get_str(access->member_name->sid));
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Found member '%s'.\n",
+	    strtab_get_str(access->member_name->sid));
+#endif
+
+	mtitem = tdata_item_new(tic_tenum);
+	tenum = tdata_enum_new();
+	mtitem->u.tenum = tenum;
+	tenum->enum_d = tebase->enum_d;
+
+	*rtitem = mtitem;
+}
+
+
 /** Type a call operation.
  *
@@ -953,19 +1271,10 @@
     tdata_item_t **rtitem)
 {
-	list_node_t *fargt_n;
-	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;
 	tdata_fun_sig_t *tsig;
 
-	int cnt;
-
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of call operation.\n");
+	cspan_print(call->expr->cspan);
+	printf(" Evaluate type of call operation.\n");
 #endif
 	/* Type the function */
@@ -986,5 +1295,6 @@
 		return;
 	default:
-		printf("Error: Calling something which is not a function ");
+		cspan_print(call->fun->cspan);
+		printf(" Error: Calling something which is not a function ");
 		printf("(found '");
 		tdata_item_print(fun_ti);
@@ -995,7 +1305,41 @@
 	}
 
-	/* Type and check the arguments. */
-	fargt_n = list_first(&tsig->arg_ti);
-	arg_n = list_first(&call->args);
+	/* Type call arguments. */
+	stype_call_args(stype, call->expr->cspan, &tsig->arg_ti, tsig->varg_ti,
+	    &call->args);
+
+	if (tsig->rtype != NULL) {
+		/* XXX Might be better to clone here. */
+		*rtitem = tsig->rtype;
+	} else {
+		*rtitem = NULL;
+	}
+}
+
+/** Type call arguments.
+ *
+ * Type arguments in call to a function or constructor.
+ *
+ * @param stype		Static typing object
+ * @param cpsan		Cspan to print in case of error.
+ * @param farg_tis	Formal argument types (list of tdata_item_t)
+ * @param args		Real arguments (list of stree_expr_t)
+ */
+static void stype_call_args(stype_t *stype, cspan_t *cspan, list_t *farg_tis,
+    tdata_item_t *fvarg_ti, list_t *args)
+{
+	list_node_t *fargt_n;
+	tdata_item_t *farg_ti;
+	tdata_item_t *varg_ti;
+
+	list_node_t *arg_n;
+	stree_expr_t *arg;
+	stree_expr_t *carg;
+
+	int cnt;
+
+	/* Type and check regular arguments. */
+	fargt_n = list_first(farg_tis);
+	arg_n = list_first(args);
 
 	cnt = 0;
@@ -1008,6 +1352,6 @@
 		if (farg_ti == NULL) {
 			/* Skip the check */
-			fargt_n = list_next(&tsig->arg_ti, fargt_n);
-			arg_n = list_next(&call->args, arg_n);
+			fargt_n = list_next(farg_tis, fargt_n);
+			arg_n = list_next(args, arg_n);
 			continue;
 		}
@@ -1019,12 +1363,12 @@
 		list_node_setdata(arg_n, carg);
 
-		fargt_n = list_next(&tsig->arg_ti, fargt_n);
-		arg_n = list_next(&call->args, arg_n);
+		fargt_n = list_next(farg_tis, fargt_n);
+		arg_n = list_next(args, arg_n);
 	}
 
 	/* Type and check variadic arguments. */
-	if (tsig->varg_ti != NULL) {
+	if (fvarg_ti != NULL) {
 		/* Obtain type of packed argument. */
-		farg_ti = tsig->varg_ti;
+		farg_ti = fvarg_ti;
 
 		/* Get array element type */
@@ -1042,23 +1386,18 @@
 			list_node_setdata(arg_n, carg);
 
-			arg_n = list_next(&call->args, arg_n);
+			arg_n = list_next(args, arg_n);
 		}
 	}
 
 	if (fargt_n != NULL) {
-		printf("Error: Too few arguments to function.\n");
+		cspan_print(cspan);
+		printf(" Error: Too few arguments.\n");
 		stype_note_error(stype);
 	}
 
 	if (arg_n != NULL) {
-		printf("Error: Too many arguments to function.\n");
-		stype_note_error(stype);
-	}
-
-	if (tsig->rtype != NULL) {
-		/* XXX Might be better to clone here. */
-		*rtitem = tsig->rtype;
-	} else {
-		*rtitem = NULL;
+		cspan_print(cspan);
+		printf(" Error: Too many arguments.\n");
+		stype_note_error(stype);
 	}
 }
@@ -1078,5 +1417,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of index operation.\n");
+	cspan_print(index->expr->cspan);
+	printf(" Evaluate type of index operation.\n");
 #endif
 	stype_expr(stype, index->base);
@@ -1103,10 +1443,24 @@
 		break;
 	case tic_tdeleg:
-		printf("Error: Indexing a delegate.\n");
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing a delegate.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tebase:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing an enum declaration.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		break;
+	case tic_tenum:
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing an enum value.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
 		break;
 	case tic_tfun:
-		printf("Error: Indexing a function.\n");
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing a function.\n");
 		stype_note_error(stype);
 		*rtitem = stype_recovery_titem(stype);
@@ -1114,5 +1468,6 @@
 	case tic_tvref:
 		/* Cannot allow this without some constraint. */
-		printf("Error: Indexing generic data.\n");
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing generic data.\n");
 		*rtitem = stype_recovery_titem(stype);
 		break;
@@ -1149,5 +1504,6 @@
 	}
 
-	printf("Error: Indexing primitive type '");
+	cspan_print(index->base->cspan);
+	printf(" Error: Indexing primitive type '");
 	tdata_item_print(base_ti);
 	printf("'.\n");
@@ -1176,5 +1532,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Indexing object type '");
+	cspan_print(index->expr->cspan);
+	printf(" Indexing object type '");
 	tdata_item_print(base_ti);
 	printf("'.\n");
@@ -1190,5 +1547,6 @@
 
 	if (idx_sym == NULL) {
-		printf("Error: Indexing object of type '");
+		cspan_print(index->base->cspan);
+		printf(" Error: Indexing object of type '");
 		tdata_item_print(base_ti);
 		printf("' which does not have an indexer.\n");
@@ -1246,5 +1604,6 @@
 		    arg->titem->u.tprimitive->tpc != tpc_int) {
 
-			printf("Error: Array index is not an integer.\n");
+			cspan_print(arg->cspan);
+			printf(" Error: Array index is not an integer.\n");
 			stype_note_error(stype);
 		}
@@ -1254,5 +1613,6 @@
 
 	if (arg_count != base_ti->u.tarray->rank) {
-		printf("Error: Using %d indices with array of rank %d.\n",
+		cspan_print(index->expr->cspan);
+		printf(" Error: Using %d indices with array of rank %d.\n",
 		    arg_count, base_ti->u.tarray->rank);
 		stype_note_error(stype);
@@ -1274,5 +1634,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of assignment.\n");
+	cspan_print(assign->expr->cspan);
+	printf(" Evaluate type of assignment.\n");
 #endif
 	stype_expr(stype, assign->dest);
@@ -1297,5 +1658,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of @c as conversion.\n");
+	cspan_print(as_op->expr->cspan);
+	printf(" Evaluate type of @c as conversion.\n");
 #endif
 	stype_expr(stype, as_op->arg);
@@ -1304,5 +1666,6 @@
 	/* Check that target type is derived from argument type. */
 	if (tdata_is_ti_derived_from_ti(titem, as_op->arg->titem) != b_true) {
-		printf("Error: Target of 'as' operator '");
+		cspan_print(as_op->dtype->cspan);
+		printf(" Error: Target of 'as' operator '");
 		tdata_item_print(titem);
 		printf("' is not derived from '");
@@ -1332,5 +1695,6 @@
 
 #ifdef DEBUG_TYPE_TRACE
-	printf("Evaluate type of boxing operation.\n");
+	cspan_print(box->expr->cspan);
+	printf(" Evaluate type of boxing operation.\n");
 #endif
 	bi = stype->program->builtin;
Index: uspace/app/sbi/src/stype_t.h
===================================================================
--- uspace/app/sbi/src/stype_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/stype_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -54,4 +54,7 @@
 	/** Block activation records */
 	list_t block_vr; /* of run_block_ar_t */
+
+	/** Number of active breakable statements (for break checking). */
+	int bstat_cnt;
 } stype_proc_vr_t;
 
Index: uspace/app/sbi/src/symbol.c
===================================================================
--- uspace/app/sbi/src/symbol.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/symbol.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -42,4 +42,5 @@
 static stree_symbol_t *symbol_find_epoint_rec(stree_program_t *prog,
     stree_ident_t *name, stree_csi_t *csi);
+static stree_symbol_t *csimbr_to_symbol(stree_csimbr_t *csimbr);
 static stree_ident_t *symbol_get_ident(stree_symbol_t *symbol);
 
@@ -88,4 +89,7 @@
 /** Lookup symbol reference in CSI.
  *
+ * XXX These functions should take just an sid, not a full identifier.
+ * Sometimes we search for a name which has no associated cspan.
+ *
  * @param prog	Program to look in
  * @param scope CSI in @a prog which is the base for references
@@ -128,55 +132,12 @@
     stree_csi_t *scope, stree_ident_t *name)
 {
-	list_node_t *node;
-	stree_csimbr_t *csimbr;
-	stree_symbol_t *symbol;
-	stree_ident_t *mbr_name;
 	stree_symbol_t *base_csi_sym;
 	stree_csi_t *base_csi;
-
-	(void) prog;
+	stree_symbol_t *symbol;
 
 	/* Look in new members in this class. */
-
-	node = list_first(&scope->members);
-	while (node != NULL) {
-		csimbr = list_node_data(node, stree_csimbr_t *);
-
-		/* Keep compiler happy. */
-		mbr_name = NULL;
-
-		switch (csimbr->cc) {
-		case csimbr_csi: mbr_name = csimbr->u.csi->name; break;
-		case csimbr_deleg: mbr_name = csimbr->u.deleg->name; break;
-		case csimbr_fun: mbr_name = csimbr->u.fun->name; break;
-		case csimbr_var: mbr_name = csimbr->u.var->name; break;
-		case csimbr_prop: mbr_name = csimbr->u.prop->name; break;
-		}
-
-		if (name->sid == mbr_name->sid) {
-			/* Match */
-			switch (csimbr->cc) {
-			case csimbr_csi:
-				symbol = csi_to_symbol(csimbr->u.csi);
-				break;
-			case csimbr_deleg:
-				symbol = deleg_to_symbol(csimbr->u.deleg);
-				break;
-			case csimbr_fun:
-				symbol = fun_to_symbol(csimbr->u.fun);
-				break;
-			case csimbr_var:
-				symbol = var_to_symbol(csimbr->u.var);
-				break;
-			case csimbr_prop:
-				symbol = prop_to_symbol(csimbr->u.prop);
-				break;
-			default:
-				assert(b_false);
-			}
-			return symbol;
-		}
-		node = list_next(&scope->members, node);
-	}
+	symbol = symbol_search_csi_no_base(prog, scope, name);
+	if (symbol != NULL)
+		return symbol;
 
 	/* Try inherited members. */
@@ -194,4 +155,42 @@
 }
 
+/** Look for symbol strictly in CSI.
+ *
+ * Look for symbol in definition of a CSI and its ancestors. (But not
+ * in lexically enclosing CSI or in base CSI.)
+ *
+ * @param prog	Program to look in
+ * @param scope CSI in which to look
+ * @param name	Identifier of the symbol
+ *
+ * @return	Symbol or @c NULL if symbol not found.
+ */
+stree_symbol_t *symbol_search_csi_no_base(stree_program_t *prog,
+    stree_csi_t *scope, stree_ident_t *name)
+{
+	list_node_t *node;
+	stree_csimbr_t *csimbr;
+	stree_ident_t *mbr_name;
+
+	(void) prog;
+
+	/* Look in new members in this class. */
+
+	node = list_first(&scope->members);
+	while (node != NULL) {
+		csimbr = list_node_data(node, stree_csimbr_t *);
+		mbr_name = stree_csimbr_get_name(csimbr);
+
+		if (name->sid == mbr_name->sid) {
+			/* Match */
+			return csimbr_to_symbol(csimbr);
+		}
+
+		node = list_next(&scope->members, node);
+	}
+	/* No match */
+	return NULL;
+}
+
 /** Look for symbol in global scope.
  *
@@ -207,9 +206,16 @@
 	stree_modm_t *modm;
 	stree_symbol_t *symbol;
+	stree_ident_t *mbr_name;
 
 	node = list_first(&prog->module->members);
 	while (node != NULL) {
 		modm = list_node_data(node, stree_modm_t *);
-		if (name->sid == modm->u.csi->name->sid) {
+
+		switch (modm->mc) {
+		case mc_csi: mbr_name = modm->u.csi->name; break;
+		case mc_enum: mbr_name = modm->u.enum_d->name; break;
+		}
+
+		if (name->sid == mbr_name->sid) {
 			/* Match */
 			switch (modm->mc) {
@@ -217,6 +223,7 @@
 				symbol = csi_to_symbol(modm->u.csi);
 				break;
-			default:
-				assert(b_false);
+			case mc_enum:
+				symbol = enum_to_symbol(modm->u.enum_d);
+				break;
 			}
 			return symbol;
@@ -346,4 +353,28 @@
 }
 
+/** Convert symbol to enum (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Enum or @c NULL if symbol is not a enum
+ */
+stree_enum_t *symbol_to_enum(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_enum)
+		return NULL;
+
+	return symbol->u.enum_d;
+}
+
+/** Convert enum to symbol (derived to base).
+ *
+ * @param deleg		Enum
+ * @return		Symbol
+ */
+stree_symbol_t *enum_to_symbol(stree_enum_t *enum_d)
+{
+	assert(enum_d->symbol);
+	return enum_d->symbol;
+}
+
 /** Convert symbol to CSI (base to derived).
  *
@@ -370,4 +401,29 @@
 }
 
+/** Convert symbol to constructor (base to derived).
+ *
+ * @param symbol	Symbol
+ * @return		Constructor or @c NULL if symbol is not a constructor
+ */
+stree_ctor_t *symbol_to_ctor(stree_symbol_t *symbol)
+{
+	if (symbol->sc != sc_ctor)
+		return NULL;
+
+	return symbol->u.ctor;
+}
+
+/** Convert constructor to symbol (derived to base).
+ *
+ * @param ctor		Constructor
+ * @return		Symbol
+ */
+stree_symbol_t *ctor_to_symbol(stree_ctor_t *ctor)
+{
+	assert(ctor->symbol);
+	return ctor->symbol;
+}
+
+
 /** Convert symbol to function (base to derived).
  *
@@ -430,4 +486,47 @@
 	return symbol->u.prop;
 }
+
+/** Get symbol from CSI member.
+ *
+ * A symbol corresponds to any CSI member. Return it.
+ *
+ * @param csimbr	CSI member
+ * @return		Symbol
+ */
+static stree_symbol_t *csimbr_to_symbol(stree_csimbr_t *csimbr)
+{
+	stree_symbol_t *symbol;
+
+	/* Keep compiler happy. */
+	symbol = NULL;
+
+	/* Match */
+	switch (csimbr->cc) {
+	case csimbr_csi:
+		symbol = csi_to_symbol(csimbr->u.csi);
+		break;
+	case csimbr_ctor:
+		symbol = ctor_to_symbol(csimbr->u.ctor);
+		break;
+	case csimbr_deleg:
+		symbol = deleg_to_symbol(csimbr->u.deleg);
+		break;
+	case csimbr_enum:
+		symbol = enum_to_symbol(csimbr->u.enum_d);
+		break;
+	case csimbr_fun:
+		symbol = fun_to_symbol(csimbr->u.fun);
+		break;
+	case csimbr_var:
+		symbol = var_to_symbol(csimbr->u.var);
+		break;
+	case csimbr_prop:
+		symbol = prop_to_symbol(csimbr->u.prop);
+		break;
+	}
+
+	return symbol;
+}
+
 
 /** Convert property to symbol (derived to base).
@@ -472,5 +571,7 @@
 	switch (symbol->sc) {
 	case sc_csi: ident = symbol->u.csi->name; break;
+	case sc_ctor: ident = symbol->u.ctor->name; break;
 	case sc_deleg: ident = symbol->u.deleg->name; break;
+	case sc_enum: ident = symbol->u.enum_d->name; break;
 	case sc_fun: ident = symbol->u.fun->name; break;
 	case sc_var: ident = symbol->u.var->name; break;
Index: uspace/app/sbi/src/symbol.h
===================================================================
--- uspace/app/sbi/src/symbol.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/symbol.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -38,4 +38,6 @@
 stree_symbol_t *symbol_search_csi(stree_program_t *prog, stree_csi_t *scope,
     stree_ident_t *name);
+stree_symbol_t *symbol_search_csi_no_base(stree_program_t *prog,
+    stree_csi_t *scope, stree_ident_t *name);
 stree_symbol_t *symbol_find_epoint(stree_program_t *prog, stree_ident_t *name);
 
@@ -44,4 +46,8 @@
 stree_csi_t *symbol_to_csi(stree_symbol_t *symbol);
 stree_symbol_t *csi_to_symbol(stree_csi_t *csi);
+stree_ctor_t *symbol_to_ctor(stree_symbol_t *symbol);
+stree_symbol_t *ctor_to_symbol(stree_ctor_t *ctor);
+stree_enum_t *symbol_to_enum(stree_symbol_t *symbol);
+stree_symbol_t *enum_to_symbol(stree_enum_t *enum_d);
 stree_fun_t *symbol_to_fun(stree_symbol_t *symbol);
 stree_symbol_t *fun_to_symbol(stree_fun_t *fun);
Index: uspace/app/sbi/src/tdata.c
===================================================================
--- uspace/app/sbi/src/tdata.c	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/tdata.c	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -48,4 +48,8 @@
 static void tdata_item_subst_tdeleg(tdata_deleg_t *torig,
     tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tebase(tdata_ebase_t *tebase,
+    tdata_tvv_t *tvv, tdata_item_t **res);
+static void tdata_item_subst_tenum(tdata_enum_t *tenum,
+    tdata_tvv_t *tvv, tdata_item_t **res);
 static void tdata_item_subst_tfun(tdata_fun_t *torig,
     tdata_tvv_t *tvv, tdata_item_t **res);
@@ -60,4 +64,6 @@
 static void tdata_tarray_print(tdata_array_t *tarray);
 static void tdata_tdeleg_print(tdata_deleg_t *tdeleg);
+static void tdata_tebase_print(tdata_ebase_t *tebase);
+static void tdata_tenum_print(tdata_enum_t *tenum);
 static void tdata_tfun_print(tdata_fun_t *tfun);
 static void tdata_tvref_print(tdata_vref_t *tvref);
@@ -157,4 +163,7 @@
 		return tdata_item_equal(a->u.tarray->base_ti,
 		    b->u.tarray->base_ti);
+	case tic_tenum:
+		/* Check if both use the same enum definition. */
+		return (a->u.tenum->enum_d == b->u.tenum->enum_d);
 	case tic_tvref:
 		/* Check if both refer to the same type argument. */
@@ -196,4 +205,10 @@
 		tdata_item_subst_tdeleg(ti->u.tdeleg, tvv, res);
 		break;
+	case tic_tebase:
+		tdata_item_subst_tebase(ti->u.tebase, tvv, res);
+		break;
+	case tic_tenum:
+		tdata_item_subst_tenum(ti->u.tenum, tvv, res);
+		break;
 	case tic_tfun:
 		tdata_item_subst_tfun(ti->u.tfun, tvv, res);
@@ -313,4 +328,42 @@
 }
 
+/** Substitute type variables in a enum-base type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tebase(tdata_ebase_t *tebase,
+    tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	tdata_ebase_t *tnew;
+
+	(void) tvv;
+
+	/* Plain copy */
+	tnew = tdata_ebase_new();
+	*res = tdata_item_new(tic_tebase);
+	(*res)->u.tebase = tebase;
+}
+
+/** Substitute type variables in a enum type item.
+ *
+ * @param torig	Type item to substitute into.
+ * @param tvv	Type variable valuation (values of type variables).
+ * @param res	Place to store pointer to new type item.
+ */
+static void tdata_item_subst_tenum(tdata_enum_t *tenum,
+    tdata_tvv_t *tvv, tdata_item_t **res)
+{
+	tdata_enum_t *tnew;
+
+	(void) tvv;
+
+	/* Plain copy */
+	tnew = tdata_enum_new();
+	*res = tdata_item_new(tic_tenum);
+	(*res)->u.tenum = tenum;
+}
+
 /** Substitute type variables in a functional type item.
  *
@@ -417,4 +470,10 @@
 	case tic_tdeleg:
 		tdata_tdeleg_print(titem->u.tdeleg);
+		break;
+	case tic_tebase:
+		tdata_tebase_print(titem->u.tebase);
+		break;
+	case tic_tenum:
+		tdata_tenum_print(titem->u.tenum);
 		break;
 	case tic_tfun:
@@ -497,4 +556,31 @@
 }
 
+/** Print enum-base type item.
+ *
+ * @param tebase		Enum-base type item
+ */
+static void tdata_tebase_print(tdata_ebase_t *tebase)
+{
+	stree_symbol_t *enum_sym;
+
+	enum_sym = enum_to_symbol(tebase->enum_d);
+
+	printf("typeref(");
+	symbol_print_fqn(enum_sym);
+	printf(")");
+}
+
+/** Print enum type item.
+ *
+ * @param tenum		Enum type item
+ */
+static void tdata_tenum_print(tdata_enum_t *tenum)
+{
+	stree_symbol_t *enum_sym;
+
+	enum_sym = enum_to_symbol(tenum->enum_d);
+	symbol_print_fqn(enum_sym);
+}
+
 /** Print function type item.
  *
@@ -624,4 +710,38 @@
 }
 
+/** Allocate new enum-base type item.
+ *
+ * @return	New enum type item
+ */
+tdata_ebase_t *tdata_ebase_new(void)
+{
+	tdata_ebase_t *tebase;
+
+	tebase = calloc(1, sizeof(tdata_ebase_t));
+	if (tebase == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tebase;
+}
+
+/** Allocate new enum type item.
+ *
+ * @return	New enum type item
+ */
+tdata_enum_t *tdata_enum_new(void)
+{
+	tdata_enum_t *tenum;
+
+	tenum = calloc(1, sizeof(tdata_enum_t));
+	if (tenum == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return tenum;
+}
+
 /** Allocate new functional type item.
  *
@@ -707,5 +827,5 @@
 }
 
-/** Set tyoe variable value.
+/** Set type variable value.
  *
  * Sets the value of variable with name SID @a name in type variable
Index: uspace/app/sbi/src/tdata.h
===================================================================
--- uspace/app/sbi/src/tdata.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/tdata.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -37,4 +37,6 @@
 tdata_primitive_t *tdata_primitive_new(tprimitive_class_t tpc);
 tdata_deleg_t *tdata_deleg_new(void);
+tdata_ebase_t *tdata_ebase_new(void);
+tdata_enum_t *tdata_enum_new(void);
 tdata_fun_t *tdata_fun_new(void);
 tdata_vref_t *tdata_vref_new(void);
Index: uspace/app/sbi/src/tdata_t.h
===================================================================
--- uspace/app/sbi/src/tdata_t.h	(revision 6c39a9074d1bf9a23bf5243a2c35b2a8549f41d3)
+++ uspace/app/sbi/src/tdata_t.h	(revision cd98e5946d71afa0ebd5f598f85d8dee47600539)
@@ -104,4 +104,21 @@
 } tdata_deleg_t;
 
+/** Enum-base type.
+ *
+ * Type for expression which reference an enum declaration. In run time
+ * enum type reference is represented by @c rdata_deleg_t. (Which is used
+ * for any symbol references).
+ */
+typedef struct {
+	/** Enum definition */
+	struct stree_enum *enum_d;
+} tdata_ebase_t;
+
+/** Enum type. */
+typedef struct {
+	/** Enum definition */
+	struct stree_enum *enum_d;
+} tdata_enum_t;
+
 /** Functional type. */
 typedef struct {
@@ -128,4 +145,8 @@
 	/** Delegate type item */
 	tic_tdeleg,
+	/** Enum-base type item */
+	tic_tebase,
+	/** Enum type item */
+	tic_tenum,
 	/** Function type item */
 	tic_tfun,
@@ -145,4 +166,6 @@
 		tdata_array_t *tarray;
 		tdata_deleg_t *tdeleg;
+		tdata_ebase_t *tebase;
+		tdata_enum_t *tenum;
 		tdata_fun_t *tfun;
 		tdata_vref_t *tvref;
