Index: Makefile
===================================================================
--- Makefile	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ Makefile	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -42,5 +42,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check distfile dist
+.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check releasefile release
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -88,16 +88,16 @@
 	$(CONFIG) $<
 
-# Distribution files
+# Release files
 
-distfile: all
-	$(MAKE) -C dist distfile
+releasefile: all
+	$(MAKE) -C release releasefile
 
-dist:
-	$(MAKE) -C dist dist
+release:
+	$(MAKE) -C release release
 
 # Cleaning
 
 distclean: clean
-	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc dist/HelenOS-*
+	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc release/HelenOS-*
 
 clean:
Index: st/Makefile
===================================================================
--- dist/Makefile	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ 	(revision )
@@ -1,70 +1,0 @@
-#
-# Copyright (c) 2011 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.
-#
-
--include ../version
--include ../Makefile.config
--include ../boot/arch/$(BARCH)/Makefile.inc
--include ../boot/Makefile.common
-
-PROFILES = amd64 arm32/GXemul arm32/integratorcp arm32/gta02 ia32 \
-    ia64/i460GX ia64/ski mips32/GXemul mips32/msim sparc64/niagara \
-    sparc64/serengeti sparc64/ultra
-
-ifdef POST_OUTPUT
-	IMGFILE = $(POST_OUTPUT)
-else
-	IMGFILE = $(BOOT_OUTPUT)
-endif
-
-SUFFIX = $(suffix $(IMGFILE))
-
-ifdef PROFILE
-	DISTFILE = Helenos-$(shell echo $(PROFILE) | tr '/' '-')$(SUFFIX)
-else
-	DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
-endif
-
-.PHONY: all clean dist distfile
-
-all: distfile
-distfile: $(DISTFILE)
-
-$(DISTFILE): $(IMGFILE)
-	cp $< $@
-
-$(IMGFILE):
-	$(MAKE) -C ..
-
-dist:
-	for profile in $(PROFILES); do \
-		$(MAKE) -C .. clean ; \
-		$(MAKE) -C .. PROFILE=$$profile distfile ; \
-	done
-
-clean:
-	rm -f $(DISTFILE)
Index: release/Makefile
===================================================================
--- release/Makefile	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ release/Makefile	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2011 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.
+#
+
+-include ../version
+
+EXPORT_DIR = /var/tmp/helenos/HelenOS-$(RELEASE)
+SRC_ARCHIVE = HelenOS-$(RELEASE).tar.bz2
+
+PROFILES = amd64 arm32/GXemul arm32/integratorcp arm32/gta02 ia32 \
+    ia64/i460GX ia64/ski mips32/GXemul mips32/msim sparc64/niagara \
+    sparc64/serengeti sparc64/ultra
+
+BZR = bzr
+TAR = tar
+
+# To determine IMG_FILE
+-include $(EXPORT_DIR)/Makefile.config
+-include $(EXPORT_DIR)/boot/arch/$(BARCH)/Makefile.inc
+-include $(EXPORT_DIR)/boot/Makefile.common
+
+ifdef POST_OUTPUT
+	IMG_FILE = $(EXPORT_DIR)/boot/$(POST_OUTPUT)
+else
+	IMG_FILE = $(EXPORT_DIR)/boot/$(BOOT_OUTPUT)
+endif
+
+SUFFIX = $(suffix $(IMG_FILE))
+
+ifdef PROFILE
+	RELEASE_FILE = HelenOS-$(RELEASE)-$(shell echo $(PROFILE) | tr '/' '-')$(SUFFIX)
+else
+	RELEASE_FILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
+endif
+
+.PHONY: all clean release releasefile export src_rel
+
+all: releasefile
+releasefile: $(RELEASE_FILE)
+
+$(RELEASE_FILE): $(IMG_FILE)
+	cp $< $@
+
+$(IMG_FILE):
+	$(MAKE) -C $(EXPORT_DIR)
+
+release: src_rel
+	for profile in $(PROFILES); do \
+		$(MAKE) -C $(EXPORT_DIR) clean ; \
+		$(MAKE) -C $(EXPORT_DIR) PROFILE=$$profile ; \
+		$(MAKE) PROFILE=$$profile releasefile ; \
+	done
+
+$(EXPORT_DIR) export:
+	rm -rf $(EXPORT_DIR)
+	mkdir -p $(EXPORT_DIR)
+	$(BZR) export $(EXPORT_DIR)
+
+src_rel $(SRC_ARCHIVE): export
+	$(TAR) -C $(shell dirname $(EXPORT_DIR)) \
+	    -cjf $(SRC_ARCHIVE) $(shell basename $(EXPORT_DIR))
+
+clean:
+	rm -f $(RELEASE_FILE)
Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/Makefile	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -35,8 +35,9 @@
 SOURCES = \
 	src/builtin/bi_boxed.c \
+	src/builtin/bi_error.c \
 	src/builtin/bi_char.c \
-	src/builtin/bi_error.c \
-	src/builtin/bi_fun.c \
+	src/builtin/bi_console.c \
 	src/builtin/bi_int.c \
+	src/builtin/bi_task.c \
 	src/builtin/bi_textfile.c \
 	src/builtin/bi_string.c \
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/builtin.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -43,6 +43,7 @@
 #include "builtin/bi_error.h"
 #include "builtin/bi_char.h"
-#include "builtin/bi_fun.h"
+#include "builtin/bi_console.h"
 #include "builtin/bi_int.h"
+#include "builtin/bi_task.h"
 #include "builtin/bi_textfile.h"
 #include "builtin/bi_string.h"
@@ -93,6 +94,7 @@
 	bi_error_declare(bi);
 	bi_char_declare(bi);
-	bi_fun_declare(bi);
+	bi_console_declare(bi);
 	bi_int_declare(bi);
+	bi_task_declare(bi);
 	bi_textfile_declare(bi);
 	bi_string_declare(bi);
@@ -111,6 +113,7 @@
 	bi_error_bind(bi);
 	bi_char_bind(bi);
-	bi_fun_bind(bi);
+	bi_console_bind(bi);
 	bi_int_bind(bi);
+	bi_task_bind(bi);
 	bi_textfile_bind(bi);
 	bi_string_bind(bi);
Index: uspace/app/sbi/src/builtin/bi_console.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_console.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/app/sbi/src/builtin/bi_console.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -0,0 +1,151 @@
+/*
+ * 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 Console builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../bigint.h"
+#include "../builtin.h"
+#include "../list.h"
+#include "../mytypes.h"
+#include "../run.h"
+#include "../stree.h"
+#include "../strtab.h"
+#include "../symbol.h"
+
+#include "bi_console.h"
+
+static void bi_console_write(run_t *run);
+static void bi_console_writeline(run_t *run);
+
+/** Declare Console builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_console_declare(builtin_t *bi)
+{
+	stree_modm_t *modm;
+	stree_csi_t *csi;
+	stree_ident_t *ident;
+	stree_symbol_t *symbol;
+	stree_symbol_t *fun_sym;
+
+	/* Declare class Builtin */
+
+	ident = stree_ident_new();
+	ident->sid = strtab_get_sid("Console");
+
+	csi = stree_csi_new(csi_class);
+	csi->name = ident;
+	list_init(&csi->targ);
+	list_init(&csi->members);
+
+	modm = stree_modm_new(mc_csi);
+	modm->u.csi = csi;
+
+	symbol = stree_symbol_new(sc_csi);
+	symbol->u.csi = csi;
+	symbol->outer_csi = NULL;
+	csi->symbol = symbol;
+
+	list_append(&bi->program->module->members, modm);
+
+	/* Declare Builtin.Write(). */
+
+	fun_sym = builtin_declare_fun(csi, "Write");
+	builtin_fun_add_arg(fun_sym, "arg");
+
+	/* Declare Builtin.WriteLine(). */
+
+	fun_sym = builtin_declare_fun(csi, "WriteLine");
+	builtin_fun_add_arg(fun_sym, "arg");
+}
+
+/** Bind builtin functions.
+ *
+ * @param bi	Builtin object
+ */
+void bi_console_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Console", "Write", bi_console_write);
+	builtin_fun_bind(bi, "Console", "WriteLine", bi_console_writeline);
+}
+
+/** Write to the console.
+ *
+ * @param run	Runner object
+ */
+static void bi_console_write(run_t *run)
+{
+	rdata_var_t *var;
+	int char_val;
+	int rc;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Console.Write()\n");
+#endif
+	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
+	assert(var);
+
+	switch (var->vc) {
+	case vc_bool:
+		printf("%s", var->u.bool_v->value ? "true" : "false");
+		break;
+	case vc_char:
+		rc = bigint_get_value_int(&var->u.char_v->value, &char_val);
+		if (rc == EOK)
+			printf("%lc", char_val);
+		else
+			printf("???");
+		break;
+	case vc_int:
+		bigint_print(&var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("%s", var->u.string_v->value);
+		break;
+	default:
+		printf("Unimplemented: Write() with unsupported type.\n");
+		exit(1);
+	}
+}
+
+/** Write a line of output.
+ *
+ * @param run	Runner object
+ */
+static void bi_console_writeline(run_t *run)
+{
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Console.WriteLine()\n");
+#endif
+	bi_console_write(run);
+	putchar('\n');
+}
Index: uspace/app/sbi/src/builtin/bi_console.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_console.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/app/sbi/src/builtin/bi_console.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -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_CONSOLE_H_
+#define BI_CONSOLE_H_
+
+#include "../mytypes.h"
+
+void bi_console_declare(builtin_t *bi);
+void bi_console_bind(builtin_t *bi);
+
+#endif
Index: pace/app/sbi/src/builtin/bi_fun.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ 	(revision )
@@ -1,219 +1,0 @@
-/*
- * 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 Builtin functions. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "../bigint.h"
-#include "../builtin.h"
-#include "../list.h"
-#include "../mytypes.h"
-#include "../os/os.h"
-#include "../run.h"
-#include "../stree.h"
-#include "../strtab.h"
-#include "../symbol.h"
-
-#include "bi_fun.h"
-
-static void bi_fun_builtin_write(run_t *run);
-static void bi_fun_builtin_writeline(run_t *run);
-static void bi_fun_task_exec(run_t *run);
-
-/** Declare builtin functions.
- *
- * @param bi	Builtin object
- */
-void bi_fun_declare(builtin_t *bi)
-{
-	stree_modm_t *modm;
-	stree_csi_t *csi;
-	stree_ident_t *ident;
-	stree_symbol_t *symbol;
-	stree_symbol_t *fun_sym;
-
-	/* Declare class Builtin */
-
-	ident = stree_ident_new();
-	ident->sid = strtab_get_sid("Builtin");
-
-	csi = stree_csi_new(csi_class);
-	csi->name = ident;
-	list_init(&csi->targ);
-	list_init(&csi->members);
-
-	modm = stree_modm_new(mc_csi);
-	modm->u.csi = csi;
-
-	symbol = stree_symbol_new(sc_csi);
-	symbol->u.csi = csi;
-	symbol->outer_csi = NULL;
-	csi->symbol = symbol;
-
-	list_append(&bi->program->module->members, modm);
-
-	/* Declare Builtin.Write(). */
-
-	fun_sym = builtin_declare_fun(csi, "Write");
-	builtin_fun_add_arg(fun_sym, "arg");
-
-	/* Declare Builtin.WriteLine(). */
-
-	fun_sym = builtin_declare_fun(csi, "WriteLine");
-	builtin_fun_add_arg(fun_sym, "arg");
-
-	/* Declare class Task. */
-
-	builtin_code_snippet(bi,
-		"class Task is\n"
-			"fun Exec(args : string[], packed), static, builtin;\n"
-		"end\n");
-}
-
-/** Bind builtin functions.
- *
- * @param bi	Builtin object
- */
-void bi_fun_bind(builtin_t *bi)
-{
-	builtin_fun_bind(bi, "Builtin", "Write", bi_fun_builtin_write);
-	builtin_fun_bind(bi, "Builtin", "WriteLine", bi_fun_builtin_writeline);
-	builtin_fun_bind(bi, "Task", "Exec", bi_fun_task_exec);
-}
-
-/** Write to the console.
- *
- * @param run	Runner object
- */
-static void bi_fun_builtin_write(run_t *run)
-{
-	rdata_var_t *var;
-	int char_val;
-	int rc;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.Write()\n");
-#endif
-	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
-	assert(var);
-
-	switch (var->vc) {
-	case vc_bool:
-		printf("%s", var->u.bool_v->value ? "true" : "false");
-		break;
-	case vc_char:
-		rc = bigint_get_value_int(&var->u.char_v->value, &char_val);
-		if (rc == EOK)
-			printf("%lc", char_val);
-		else
-			printf("???");
-		break;
-	case vc_int:
-		bigint_print(&var->u.int_v->value);
-		break;
-	case vc_string:
-		printf("%s", var->u.string_v->value);
-		break;
-	default:
-		printf("Unimplemented: Write() with unsupported type.\n");
-		exit(1);
-	}
-}
-
-/** Write a line of output.
- *
- * @param run	Runner object
- */
-static void bi_fun_builtin_writeline(run_t *run)
-{
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.WriteLine()\n");
-#endif
-	bi_fun_builtin_write(run);
-	putchar('\n');
-}
-
-/** Start an executable and wait for it to finish.
- *
- * @param run	Runner object
- */
-static void bi_fun_task_exec(run_t *run)
-{
-	rdata_var_t *args;
-	rdata_var_t *var;
-	rdata_array_t *array;
-	rdata_var_t *arg;
-	int idx, dim;
-	const char **cmd;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Task.Exec()\n");
-#endif
-	args = run_local_vars_lookup(run, strtab_get_sid("args"));
-
-	assert(args);
-	assert(args->vc == vc_ref);
-
-	var = args->u.ref_v->vref;
-	assert(var->vc == vc_array);
-
-	array = var->u.array_v;
-	assert(array->rank == 1);
-	dim = array->extent[0];
-
-	if (dim == 0) {
-		printf("Error: Builtin.Exec() expects at least one argument.\n");
-		exit(1);
-	}
-
-	cmd = calloc(dim + 1, sizeof(char *));
-	if (cmd == NULL) {
-		printf("Memory allocation failed.\n");
-		exit(1);
-	}
-
-	for (idx = 0; idx < dim; ++idx) {
-		arg = array->element[idx];
-		if (arg->vc != vc_string) {
-			printf("Error: Argument to Builtin.Exec() must be "
-			    "string (found %d).\n", arg->vc);
-			exit(1);
-		}
-
-		cmd[idx] = arg->u.string_v->value;
-	}
-
-	cmd[dim] = '\0';
-
-	if (os_exec((char * const *)cmd) != EOK) {
-		printf("Error: Exec failed.\n");
-		exit(1);
-	}
-}
Index: pace/app/sbi/src/builtin/bi_fun.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ 	(revision )
@@ -1,37 +1,0 @@
-/*
- * 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_FUN_H_
-#define BI_FUN_H_
-
-#include "../mytypes.h"
-
-void bi_fun_declare(builtin_t *bi);
-void bi_fun_bind(builtin_t *bi);
-
-#endif
Index: uspace/app/sbi/src/builtin/bi_task.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_task.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/app/sbi/src/builtin/bi_task.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -0,0 +1,122 @@
+/*
+ * 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 Task builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../builtin.h"
+#include "../list.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../run.h"
+#include "../strtab.h"
+
+#include "bi_task.h"
+
+static void bi_task_exec(run_t *run);
+
+/** Declare task builtin.
+ *
+ * @param bi	Builtin object
+ */
+void bi_task_declare(builtin_t *bi)
+{
+	builtin_code_snippet(bi,
+		"class Task is\n"
+			"fun Exec(args : string[], packed), static, builtin;\n"
+		"end\n");
+}
+
+/** Bind builtin functions.
+ *
+ * @param bi	Builtin object
+ */
+void bi_task_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Task", "Exec", bi_task_exec);
+}
+
+/** Start an executable and wait for it to finish.
+ *
+ * @param run	Runner object
+ */
+static void bi_task_exec(run_t *run)
+{
+	rdata_var_t *args;
+	rdata_var_t *var;
+	rdata_array_t *array;
+	rdata_var_t *arg;
+	int idx, dim;
+	const char **cmd;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Task.Exec()\n");
+#endif
+	args = run_local_vars_lookup(run, strtab_get_sid("args"));
+
+	assert(args);
+	assert(args->vc == vc_ref);
+
+	var = args->u.ref_v->vref;
+	assert(var->vc == vc_array);
+
+	array = var->u.array_v;
+	assert(array->rank == 1);
+	dim = array->extent[0];
+
+	if (dim == 0) {
+		printf("Error: Builtin.Exec() expects at least one argument.\n");
+		exit(1);
+	}
+
+	cmd = calloc(dim + 1, sizeof(char *));
+	if (cmd == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	for (idx = 0; idx < dim; ++idx) {
+		arg = array->element[idx];
+		if (arg->vc != vc_string) {
+			printf("Error: Argument to Builtin.Exec() must be "
+			    "string (found %d).\n", arg->vc);
+			exit(1);
+		}
+
+		cmd[idx] = arg->u.string_v->value;
+	}
+
+	cmd[dim] = '\0';
+
+	if (os_exec((char * const *)cmd) != EOK) {
+		printf("Error: Exec failed.\n");
+		exit(1);
+	}
+}
Index: uspace/app/sbi/src/builtin/bi_task.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_task.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/app/sbi/src/builtin/bi_task.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -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_TASK_H_
+#define BI_TASK_H_
+
+#include "../mytypes.h"
+
+void bi_task_declare(builtin_t *bi);
+void bi_task_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/imode.c
===================================================================
--- uspace/app/sbi/src/imode.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/imode.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -178,4 +178,17 @@
 			/* Convert expression result to value item. */
 			run_cvt_value_item(&run, rexpr, &rexpr_vi);
+			rdata_item_destroy(rexpr);
+
+			/* Check for unhandled exceptions. */
+			run_exc_check_unhandled(&run);
+		} else {
+			rexpr_vi = NULL;
+		}
+
+		/*
+		 * rexpr_vi can be NULL if either repxr was null or
+		 * if the conversion to value item raised an exception.
+		 */
+		if (rexpr_vi != NULL) {
 			assert(rexpr_vi->ic == ic_value);
 
@@ -184,6 +197,10 @@
 			rdata_value_print(rexpr_vi->u.value);
 			printf("\n");
+
+			rdata_item_destroy(rexpr_vi);
 		}
 	}
+
+	run_proc_ar_destroy(&run, proc_ar);
 
 	/* Remove block visit record from the stack, */
Index: uspace/app/sbi/src/intmap.c
===================================================================
--- uspace/app/sbi/src/intmap.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/intmap.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -50,4 +50,15 @@
 }
 
+/** Deinitialize map.
+ *
+ * The map must be already empty.
+ *
+ * @param intmap	Map to initialize.
+ */
+void intmap_fini(intmap_t *intmap)
+{
+	list_fini(&intmap->elem);
+}
+
 /** Set value corresponding to a key.
  *
@@ -56,7 +67,7 @@
  * is removed from the map.
  *
- * @param intmap	Map.
- * @param key		Key (integer).
- * @param value		Value (must be a pointer) or @c NULL.
+ * @param intmap	Map
+ * @param key		Key (integer)
+ * @param value		Value (must be a pointer) or @c NULL
  */
 void intmap_set(intmap_t *intmap, int key, void *value)
@@ -75,6 +86,5 @@
 				/* Remove map element. */
 				list_remove(&intmap->elem, node);
-				node->data = NULL;
-				free(node);
+				free(elem);
 			}
 			return;
@@ -98,6 +108,6 @@
 /** Get value corresponding to a key.
  *
- * @param intmap	Map.
- * @param key		Key for which to retrieve mapping.
+ * @param intmap	Map
+ * @param key		Key for which to retrieve mapping
  *
  * @return		Value correspoding to @a key or @c NULL if no mapping
@@ -121,2 +131,45 @@
 	return NULL;
 }
+
+/** Get first element in the map.
+ *
+ * For iterating over the map, this returns the first element (in no
+ * particular order).
+ *
+ * @param intmap	Map
+ * @return		Map element or NULL if the map is empty
+ */
+map_elem_t *intmap_first(intmap_t *intmap)
+{
+	list_node_t *node;
+
+	node = list_first(&intmap->elem);
+	if (node == NULL)
+		return NULL;
+
+	return list_node_data(node, map_elem_t *);
+}
+
+/** Get element key.
+ *
+ * Giver a map element, return the key.
+ *
+ * @param elem		Map element
+ * @return		Key
+ */
+int intmap_elem_get_key(map_elem_t *elem)
+{
+	return elem->key;
+}
+
+/** Get element value.
+ *
+ * Giver a map element, return the value.
+ *
+ * @param elem		Map element
+ * @return		Value
+ */
+void *intmap_elem_get_value(map_elem_t *elem)
+{
+	return elem->value;
+}
Index: uspace/app/sbi/src/intmap.h
===================================================================
--- uspace/app/sbi/src/intmap.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/intmap.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -33,6 +33,10 @@
 
 void intmap_init(intmap_t *intmap);
+void intmap_fini(intmap_t *intmap);
 void intmap_set(intmap_t *intmap, int key, void *data);
 void *intmap_get(intmap_t *intmap, int key);
+map_elem_t *intmap_first(intmap_t *intmap);
+int intmap_elem_get_key(map_elem_t *elem);
+void *intmap_elem_get_value(map_elem_t *elem);
 
 #endif
Index: uspace/app/sbi/src/lex.c
===================================================================
--- uspace/app/sbi/src/lex.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/lex.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -45,4 +45,9 @@
 #define TAB_WIDTH 8
 
+typedef enum {
+	cs_chr,
+	cs_str
+} chr_str_t;
+
 static void lex_touch(lex_t *lex);
 static bool_t lex_read_try(lex_t *lex);
@@ -57,4 +62,5 @@
 static void lex_number(lex_t *lex);
 static void lex_string(lex_t *lex);
+static void lex_char_string_core(lex_t *lex, chr_str_t cs);
 static int digit_value(char c);
 
@@ -117,4 +123,5 @@
 	{ lc_string,	"string" },
 	{ lc_struct,	"struct" },
+	{ lc_switch,	"switch" },
 	{ lc_then,	"then" },
 	{ lc_this,	"this" },
@@ -122,4 +129,5 @@
 	{ lc_var,	"var" },
 	{ lc_with,	"with" },
+	{ lc_when,	"when" },
 	{ lc_while,	"while" },
 	{ lc_yield,	"yield" },
@@ -535,30 +543,9 @@
 static void lex_char(lex_t *lex)
 {
-	char *bp;
-	int idx;
 	size_t len;
 	int char_val;
 
-	bp = lex->ibp + 1;
-	idx = 0;
-
-	while (bp[idx] != '\'') {
-		if (idx >= SLBUF_SIZE) {
-			printf("Error: Character literal too long.\n");
-			exit(1);
-		}
-
-		if (bp[idx] == '\0') {
-			printf("Error: Unterminated character literal.\n");
-			exit(1);
-		}
-
-		strlit_buf[idx] = bp[idx];
-		++idx;
-	}
-
-	lex->ibp = bp + idx + 1;
-
-	strlit_buf[idx] = '\0';
+	lex_char_string_core(lex, cs_chr);
+
 	len = os_str_length(strlit_buf);
 	if (len != 1) {
@@ -620,31 +607,84 @@
 static void lex_string(lex_t *lex)
 {
-	char *bp;
-	int idx;
-
-	bp = lex->ibp + 1;
-	idx = 0;
-
-	while (bp[idx] != '"') {
-		if (idx >= SLBUF_SIZE) {
-			printf("Error: String literal too long.\n");
-			exit(1);
-		}
-
-		if (bp[idx] == '\0') {
-			printf("Error: Unterminated string literal.\n");
-			exit(1);
-		}
-
-		strlit_buf[idx] = bp[idx];
-		++idx;
-	}
-
-	lex->ibp = bp + idx + 1;
-
-	strlit_buf[idx] = '\0';
+	lex_char_string_core(lex, cs_str);
 
 	lex->current.lclass = lc_lit_string;
 	lex->current.u.lit_string.value = os_str_dup(strlit_buf);
+}
+
+static void lex_char_string_core(lex_t *lex, chr_str_t cs)
+{
+	char *bp;
+	int sidx, didx;
+	char term;
+	const char *descr, *cap_descr;
+	char spchar;
+
+	/* Make compiler happy */
+	term = '\0';
+	descr = NULL;
+	cap_descr = NULL;
+
+	switch (cs) {
+	case cs_chr:
+		term = '\'';
+		descr = "character";
+		cap_descr = "Character";
+		break;
+	case cs_str:
+		term = '"';
+		descr = "string";
+		cap_descr = "String";
+		break;
+	}
+
+	bp = lex->ibp + 1;
+	sidx = didx = 0;
+
+	while (bp[sidx] != term) {
+		if (didx >= SLBUF_SIZE) {
+			printf("Error: %s literal too long.\n", cap_descr);
+			exit(1);
+		}
+
+		if (bp[sidx] == '\0') {
+			printf("Error: Unterminated %s literal.\n", descr);
+			exit(1);
+		}
+
+		if (bp[sidx] == '\\') {
+			switch (bp[sidx + 1]) {
+			case '\\':
+				spchar = '\\';
+				break;
+			case '\'':
+				spchar = '\'';
+				break;
+			case '"':
+				spchar = '"';
+				break;
+			case 'n':
+				spchar = '\n';
+				break;
+			case 't':
+				spchar = '\t';
+				break;
+			default:
+				printf("Error: Unknown character escape sequence.\n");
+				exit(1);
+			}
+
+			strlit_buf[didx] = spchar;
+			++didx;
+			sidx += 2;
+		} else {
+			strlit_buf[didx] = bp[sidx];
+			++sidx; ++didx;
+		}
+	}
+
+	lex->ibp = bp + sidx + 1;
+
+	strlit_buf[didx] = '\0';
 }
 
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/lex_t.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -85,4 +85,5 @@
 	lc_string,
 	lc_struct,
+	lc_switch,
 	lc_then,
 	lc_this,
@@ -90,4 +91,5 @@
 	lc_var,
 	lc_with,
+	lc_when,
 	lc_while,
 	lc_yield,
Index: uspace/app/sbi/src/list.c
===================================================================
--- uspace/app/sbi/src/list.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/list.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -57,4 +57,16 @@
 }
 
+/** Deinitialize list.
+ *
+ * @param list	List to deinitialize.
+ */
+void list_fini(list_t *list)
+{
+	assert(list_is_empty(list));
+
+	list->head.prev = NULL;
+	list->head.next = NULL;
+}
+
 /** Append data to list.
  *
Index: uspace/app/sbi/src/list.h
===================================================================
--- uspace/app/sbi/src/list.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/list.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,4 +34,5 @@
 
 void list_init(list_t *list);
+void list_fini(list_t *list);
 void list_append(list_t *list, void *data);
 void list_prepend(list_t *list, void *data);
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/parse.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -82,4 +82,5 @@
 static stree_vdecl_t *parse_vdecl(parse_t *parse);
 static stree_if_t *parse_if(parse_t *parse);
+static stree_switch_t *parse_switch(parse_t *parse);
 static stree_while_t *parse_while(parse_t *parse);
 static stree_for_t *parse_for(parse_t *parse);
@@ -667,5 +668,4 @@
 	stree_prop_t *prop;
 	stree_symbol_t *symbol;
-	bool_t body_expected;
 
 	stree_ident_t *ident;
@@ -720,6 +720,4 @@
 	/* Parse attributes. */
 	parse_symbol_attrs(parse, symbol);
-
-	body_expected = (outer_csi->cc != csi_interface);
 
 	lmatch(parse, lc_is);
@@ -1070,4 +1068,5 @@
 	stree_vdecl_t *vdecl_s;
 	stree_if_t *if_s;
+	stree_switch_t *switch_s;
 	stree_while_t *while_s;
 	stree_for_t *for_s;
@@ -1092,4 +1091,9 @@
 		stat->u.if_s = if_s;
 		break;
+	case lc_switch:
+		switch_s = parse_switch(parse);
+		stat = stree_stat_new(st_switch);
+		stat->u.switch_s = switch_s;
+		break;
 	case lc_while:
 		while_s = parse_while(parse);
@@ -1214,4 +1218,58 @@
 	lmatch(parse, lc_end);
 	return if_s;
+}
+
+/** Parse @c switch statement.
+ *
+ * @param parse		Parser object.
+ * @return		New syntax tree node.
+ */
+static stree_switch_t *parse_switch(parse_t *parse)
+{
+	stree_switch_t *switch_s;
+	stree_when_t *when_c;
+	stree_expr_t *expr;
+
+#ifdef DEBUG_PARSE_TRACE
+	printf("Parse 'switch' statement.\n");
+#endif
+	lmatch(parse, lc_switch);
+
+	switch_s = stree_switch_new();
+	list_init(&switch_s->when_clauses);
+
+	switch_s->expr = parse_expr(parse);
+	lmatch(parse, lc_is);
+
+	/* Parse @c when clauses. */
+	while (lcur_lc(parse) == lc_when) {
+		lskip(parse);
+		when_c = stree_when_new();
+		list_init(&when_c->exprs);
+		while (b_true) {
+			expr = parse_expr(parse);
+			list_append(&when_c->exprs, expr);
+			if (lcur_lc(parse) != lc_comma)
+				break;
+			lskip(parse);
+		}
+
+		lmatch(parse, lc_do);
+		when_c->block = parse_block(parse);
+
+		list_append(&switch_s->when_clauses, when_c);
+	}
+
+	/* Parse @c else clause. */
+	if (lcur_lc(parse) == lc_else) {
+		lskip(parse);
+		lmatch(parse, lc_do);
+		switch_s->else_block = parse_block(parse);
+	} else {
+		switch_s->else_block = NULL;
+	}
+
+	lmatch(parse, lc_end);
+	return switch_s;
 }
 
@@ -1654,4 +1712,5 @@
 	case lc_except:
 	case lc_finally:
+	case lc_when:
 		return b_true;
 	default:
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/rdata.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -49,4 +49,5 @@
 #include <assert.h>
 #include "bigint.h"
+#include "list.h"
 #include "mytypes.h"
 #include "stree.h"
@@ -69,5 +70,20 @@
 static void rdata_symbol_copy(rdata_symbol_t *src, rdata_symbol_t **dest);
 
+static void rdata_var_destroy_inner(rdata_var_t *var);
+
+static void rdata_bool_destroy(rdata_bool_t *bool_v);
+static void rdata_char_destroy(rdata_char_t *char_v);
+static void rdata_int_destroy(rdata_int_t *int_v);
+static void rdata_string_destroy(rdata_string_t *string_v);
+static void rdata_ref_destroy(rdata_ref_t *ref_v);
+static void rdata_deleg_destroy(rdata_deleg_t *deleg_v);
+static void rdata_enum_destroy(rdata_enum_t *enum_v);
+static void rdata_array_destroy(rdata_array_t *array_v);
+static void rdata_object_destroy(rdata_object_t *object_v);
+static void rdata_resource_destroy(rdata_resource_t *resource_v);
+static void rdata_symbol_destroy(rdata_symbol_t *symbol_v);
+
 static int rdata_array_get_dim(rdata_array_t *array);
+static void rdata_var_copy_to(rdata_var_t *src, rdata_var_t *dest);
 
 static void rdata_address_print(rdata_address_t *address);
@@ -414,5 +430,5 @@
 /** Allocate array elements.
  *
- * Allocates var nodes for elements of @a array.
+ * Allocates element array of @a array.
  *
  * @param array		Array.
@@ -420,5 +436,5 @@
 void rdata_array_alloc_element(rdata_array_t *array)
 {
-	int dim, idx;
+	int dim;
 
 	dim = rdata_array_get_dim(array);
@@ -428,12 +444,4 @@
 		printf("Memory allocation failed.\n");
 		exit(1);
-	}
-
-	for (idx = 0; idx < dim; ++idx) {
-		array->element[idx] = calloc(1, sizeof(rdata_var_t));
-		if (array->element[idx] == NULL) {
-			printf("Memory allocation failed.\n");
-			exit(1);
-		}
 	}
 }
@@ -457,4 +465,207 @@
 }
 
+/** Deallocate item.
+ *
+ * @param item	Item node
+ */
+void rdata_item_delete(rdata_item_t *item)
+{
+	assert(item != NULL);
+	free(item);
+}
+
+/** Deallocate variable address.
+ *
+ * @param addr_var	Variable address node
+ */
+void rdata_addr_var_delete(rdata_addr_var_t *addr_var)
+{
+	assert(addr_var != NULL);
+	free(addr_var);
+}
+
+/** Deallocate property address.
+ *
+ * @param addr_prop	Variable address node
+ */
+void rdata_addr_prop_delete(rdata_addr_prop_t *addr_prop)
+{
+	assert(addr_prop != NULL);
+	free(addr_prop);
+}
+
+/** Deallocate named property address.
+ *
+ * @param aprop_named	Variable address node
+ */
+void rdata_aprop_named_delete(rdata_aprop_named_t *aprop_named)
+{
+	assert(aprop_named != NULL);
+	free(aprop_named);
+}
+
+/** Deallocate indexed property address.
+ *
+ * @param aprop_indexed	Variable address node
+ */
+void rdata_aprop_indexed_delete(rdata_aprop_indexed_t *aprop_indexed)
+{
+	assert(aprop_indexed != NULL);
+	free(aprop_indexed);
+}
+
+/** Deallocate address.
+ *
+ * @param address	Address node
+ */
+void rdata_address_delete(rdata_address_t *address)
+{
+	assert(address != NULL);
+	free(address);
+}
+
+/** Deallocate value.
+ *
+ * @param value		Value node
+ */
+void rdata_value_delete(rdata_value_t *value)
+{
+	assert(value != NULL);
+	free(value);
+}
+
+/** Deallocate var node.
+ *
+ * @param var	Var node
+ */
+void rdata_var_delete(rdata_var_t *var)
+{
+	assert(var != NULL);
+	free(var);
+}
+
+/** Deallocate boolean.
+ *
+ * @param bool_v		Boolean
+ */
+void rdata_bool_delete(rdata_bool_t *bool_v)
+{
+	assert(bool_v != NULL);
+	free(bool_v);
+}
+
+/** Deallocate character.
+ *
+ * @param char_v	Character
+ */
+void rdata_char_delete(rdata_char_t *char_v)
+{
+	assert(char_v != NULL);
+	free(char_v);
+}
+
+/** Deallocate integer.
+ *
+ * @param int_v		Integer
+ */
+void rdata_int_delete(rdata_int_t *int_v)
+{
+	assert(int_v != NULL);
+	free(int_v);
+}
+
+/** Deallocate string.
+ *
+ * @param string_v	String
+ */
+void rdata_string_delete(rdata_string_t *string_v)
+{
+	assert(string_v != NULL);
+	free(string_v);
+}
+
+/** Deallocate reference.
+ *
+ * @param ref_v		Reference
+ */
+void rdata_ref_delete(rdata_ref_t *ref_v)
+{
+	assert(ref_v != NULL);
+	free(ref_v);
+}
+
+/** Deallocate delegate.
+ *
+ * @param deleg_v		Reference
+ */
+void rdata_deleg_delete(rdata_deleg_t *deleg_v)
+{
+	assert(deleg_v != NULL);
+	free(deleg_v);
+}
+
+/** Deallocate enum.
+ *
+ * @param enum_v		Reference
+ */
+void rdata_enum_delete(rdata_enum_t *enum_v)
+{
+	assert(enum_v != NULL);
+	free(enum_v);
+}
+
+/** Deallocate array.
+ *
+ * @param array_v		Array
+ */
+void rdata_array_delete(rdata_array_t *array_v)
+{
+	assert(array_v != NULL);
+	free(array_v);
+}
+
+/** Deallocate object.
+ *
+ * @param object_v		Object
+ */
+void rdata_object_delete(rdata_object_t *object_v)
+{
+	assert(object_v != NULL);
+	free(object_v);
+}
+
+/** Deallocate resource.
+ *
+ * @param resource_v		Resource
+ */
+void rdata_resource_delete(rdata_resource_t *resource_v)
+{
+	assert(resource_v != NULL);
+	free(resource_v);
+}
+
+/** Deallocate symbol.
+ *
+ * @param symbol_v		Symbol
+ */
+void rdata_symbol_delete(rdata_symbol_t *symbol_v)
+{
+	assert(symbol_v != NULL);
+	free(symbol_v);
+}
+
+/** Copy value.
+ *
+ * @param src		Input value
+ * @param dest		Place to store pointer to new value
+ */
+void rdata_value_copy(rdata_value_t *src, rdata_value_t **dest)
+{
+	assert(src != NULL);
+
+	*dest = rdata_value_new();
+	rdata_var_copy(src->var, &(*dest)->var);
+}
+
 /** Make copy of a variable.
  *
@@ -470,48 +681,64 @@
 
 	nvar = rdata_var_new(src->vc);
+	rdata_var_copy_to(src, nvar);
+
+	*dest = nvar;
+}
+
+/** Copy variable content to another variable.
+ *
+ * Writes an exact copy of an existing var node to another var node.
+ * The varclass of @a src and @a dest must match. The content of
+ * @a dest.u must be invalid.
+ *
+ * @param src		Source var node.
+ * @param dest		Destination var node.
+ */
+static void rdata_var_copy_to(rdata_var_t *src, rdata_var_t *dest)
+{
+	dest->vc = src->vc;
 
 	switch (src->vc) {
 	case vc_bool:
-		rdata_bool_copy(src->u.bool_v, &nvar->u.bool_v);
+		rdata_bool_copy(src->u.bool_v, &dest->u.bool_v);
 		break;
 	case vc_char:
-		rdata_char_copy(src->u.char_v, &nvar->u.char_v);
+		rdata_char_copy(src->u.char_v, &dest->u.char_v);
 		break;
 	case vc_int:
-		rdata_int_copy(src->u.int_v, &nvar->u.int_v);
+		rdata_int_copy(src->u.int_v, &dest->u.int_v);
 		break;
 	case vc_string:
-		rdata_string_copy(src->u.string_v, &nvar->u.string_v);
+		rdata_string_copy(src->u.string_v, &dest->u.string_v);
 		break;
 	case vc_ref:
-		rdata_ref_copy(src->u.ref_v, &nvar->u.ref_v);
+		rdata_ref_copy(src->u.ref_v, &dest->u.ref_v);
 		break;
 	case vc_deleg:
-		rdata_deleg_copy(src->u.deleg_v, &nvar->u.deleg_v);
+		rdata_deleg_copy(src->u.deleg_v, &dest->u.deleg_v);
 		break;
 	case vc_enum:
-		rdata_enum_copy(src->u.enum_v, &nvar->u.enum_v);
+		rdata_enum_copy(src->u.enum_v, &dest->u.enum_v);
 		break;
 	case vc_array:
-		rdata_array_copy(src->u.array_v, &nvar->u.array_v);
+		rdata_array_copy(src->u.array_v, &dest->u.array_v);
 		break;
 	case vc_object:
-		rdata_object_copy(src->u.object_v, &nvar->u.object_v);
+		rdata_object_copy(src->u.object_v, &dest->u.object_v);
 		break;
 	case vc_resource:
-		rdata_resource_copy(src->u.resource_v, &nvar->u.resource_v);
+		rdata_resource_copy(src->u.resource_v, &dest->u.resource_v);
 		break;
 	case vc_symbol:
-		rdata_symbol_copy(src->u.symbol_v, &nvar->u.symbol_v);
-		break;
-	}
-
-	*dest = nvar;
-}
+		rdata_symbol_copy(src->u.symbol_v, &dest->u.symbol_v);
+		break;
+	}
+}
+
 
 /** Copy boolean.
  *
- * @param src		Source boolean.
- * @param dest		Place to store pointer to new boolean.
+ * @param src		Source boolean
+ * @param dest		Place to store pointer to new boolean
  */
 static void rdata_bool_copy(rdata_bool_t *src, rdata_bool_t **dest)
@@ -523,6 +750,6 @@
 /** Copy character.
  *
- * @param src		Source character.
- * @param dest		Place to store pointer to new character.
+ * @param src		Source character
+ * @param dest		Place to store pointer to new character
  */
 static void rdata_char_copy(rdata_char_t *src, rdata_char_t **dest)
@@ -534,6 +761,6 @@
 /** Copy integer.
  *
- * @param src		Source integer.
- * @param dest		Place to store pointer to new integer.
+ * @param src		Source integer
+ * @param dest		Place to store pointer to new integer
  */
 static void rdata_int_copy(rdata_int_t *src, rdata_int_t **dest)
@@ -632,4 +859,355 @@
 	*dest = rdata_symbol_new();
 	(*dest)->sym = src->sym;
+}
+
+/** Destroy var node.
+ *
+ * @param var	Var node
+ */
+void rdata_var_destroy(rdata_var_t *var)
+{
+	/* First destroy class-specific part */
+	rdata_var_destroy_inner(var);
+
+	/* Deallocate var node */
+	rdata_var_delete(var);
+}
+
+/** Destroy inside of var node.
+ *
+ * Destroy content of var node, but do not deallocate the var node
+ * itself.
+ *
+ * @param var	Var node
+ */
+static void rdata_var_destroy_inner(rdata_var_t *var)
+{
+	/* First destroy class-specific part */
+
+	switch (var->vc) {
+	case vc_bool:
+		rdata_bool_destroy(var->u.bool_v);
+		break;
+	case vc_char:
+		rdata_char_destroy(var->u.char_v);
+		break;
+	case vc_int:
+		rdata_int_destroy(var->u.int_v);
+		break;
+	case vc_string:
+		rdata_string_destroy(var->u.string_v);
+		break;
+	case vc_ref:
+		rdata_ref_destroy(var->u.ref_v);
+		break;
+	case vc_deleg:
+		rdata_deleg_destroy(var->u.deleg_v);
+		break;
+	case vc_enum:
+		rdata_enum_destroy(var->u.enum_v);
+		break;
+	case vc_array:
+		rdata_array_destroy(var->u.array_v);
+		break;
+	case vc_object:
+		rdata_object_destroy(var->u.object_v);
+		break;
+	case vc_resource:
+		rdata_resource_destroy(var->u.resource_v);
+		break;
+	case vc_symbol:
+		rdata_symbol_destroy(var->u.symbol_v);
+		break;
+	}
+}
+
+/** Destroy item.
+ *
+ * Destroy an item including the value or address within.
+ *
+ * @param item	Item
+ */
+void rdata_item_destroy(rdata_item_t *item)
+{
+	/* First destroy class-specific part */
+
+	switch (item->ic) {
+	case ic_address:
+		rdata_address_destroy(item->u.address);
+		break;
+	case ic_value:
+		rdata_value_destroy(item->u.value);
+		break;
+	}
+
+	/* Deallocate item node */
+	rdata_item_delete(item);
+}
+
+/** Destroy address.
+ *
+ * Destroy an address node.
+ *
+ * @param address	Address
+ */
+void rdata_address_destroy(rdata_address_t *address)
+{
+	switch (address->ac) {
+	case ac_var:
+		rdata_addr_var_destroy(address->u.var_a);
+		break;
+	case ac_prop:
+		rdata_addr_prop_destroy(address->u.prop_a);
+		break;
+	}
+
+	/* Deallocate address node */
+	rdata_address_delete(address);
+}
+
+/** Destroy variable address.
+ *
+ * Destroy a variable address node.
+ *
+ * @param addr_var	Variable address
+ */
+void rdata_addr_var_destroy(rdata_addr_var_t *addr_var)
+{
+	addr_var->vref = NULL;
+
+	/* Deallocate variable address node */
+	rdata_addr_var_delete(addr_var);
+}
+
+/** Destroy property address.
+ *
+ * Destroy a property address node.
+ *
+ * @param addr_prop	Property address
+ */
+void rdata_addr_prop_destroy(rdata_addr_prop_t *addr_prop)
+{
+	switch (addr_prop->apc) {
+	case apc_named:
+		rdata_aprop_named_destroy(addr_prop->u.named);
+		break;
+	case apc_indexed:
+		rdata_aprop_indexed_destroy(addr_prop->u.indexed);
+		break;
+	}
+
+	if (addr_prop->tvalue != NULL) {
+		rdata_value_destroy(addr_prop->tvalue);
+		addr_prop->tvalue = NULL;
+	}
+
+	addr_prop->tpos = NULL;
+
+	/* Deallocate property address node */
+	rdata_addr_prop_delete(addr_prop);
+}
+
+/** Destroy named property address.
+ *
+ * Destroy a named property address node.
+ *
+ * @param aprop_named	Named property address
+ */
+void rdata_aprop_named_destroy(rdata_aprop_named_t *aprop_named)
+{
+	rdata_deleg_destroy(aprop_named->prop_d);
+
+	/* Deallocate named property address node */
+	rdata_aprop_named_delete(aprop_named);
+}
+
+/** Destroy indexed property address.
+ *
+ * Destroy a indexed property address node.
+ *
+ * @param aprop_indexed		Indexed property address
+ */
+void rdata_aprop_indexed_destroy(rdata_aprop_indexed_t *aprop_indexed)
+{
+	list_node_t *arg_node;
+	rdata_item_t *arg_i;
+
+	/* Destroy the object delegate. */
+	rdata_deleg_destroy(aprop_indexed->object_d);
+
+	/*
+	 * Walk through all argument items (indices) and destroy them,
+	 * removing them from the list as well.
+	 */
+	while (!list_is_empty(&aprop_indexed->args)) {
+		arg_node = list_first(&aprop_indexed->args);
+		arg_i = list_node_data(arg_node, rdata_item_t *);
+
+		rdata_item_destroy(arg_i);
+		list_remove(&aprop_indexed->args, arg_node);
+	}
+
+	/* Destroy the now empty list */
+	list_fini(&aprop_indexed->args);
+
+	/* Deallocate indexed property address node */
+	rdata_aprop_indexed_delete(aprop_indexed);
+}
+
+/** Destroy value.
+ *
+ * Destroy a value node.
+ *
+ * @param value		Value
+ */
+void rdata_value_destroy(rdata_value_t *value)
+{
+	/* Assumption: Var nodes in values are not shared. */
+	rdata_var_destroy(value->var);
+
+	/* Deallocate value node */
+	rdata_value_delete(value);
+}
+
+/** Destroy boolean.
+ *
+ * @param bool_v		Boolean
+ */
+static void rdata_bool_destroy(rdata_bool_t *bool_v)
+{
+	rdata_bool_delete(bool_v);
+}
+
+/** Destroy character.
+ *
+ * @param char_v	Character
+ */
+static void rdata_char_destroy(rdata_char_t *char_v)
+{
+	bigint_destroy(&char_v->value);
+	rdata_char_delete(char_v);
+}
+
+/** Destroy integer.
+ *
+ * @param int_v		Integer
+ */
+static void rdata_int_destroy(rdata_int_t *int_v)
+{
+	bigint_destroy(&int_v->value);
+	rdata_int_delete(int_v);
+}
+
+/** Destroy string.
+ *
+ * @param string_v	String
+ */
+static void rdata_string_destroy(rdata_string_t *string_v)
+{
+	/*
+	 * String values are shared so we cannot free them. Just deallocate
+	 * the node.
+	 */
+	rdata_string_delete(string_v);
+}
+
+/** Destroy reference.
+ *
+ * @param ref_v		Reference
+ */
+static void rdata_ref_destroy(rdata_ref_t *ref_v)
+{
+	ref_v->vref = NULL;
+	rdata_ref_delete(ref_v);
+}
+
+/** Destroy delegate.
+ *
+ * @param deleg_v		Reference
+ */
+static void rdata_deleg_destroy(rdata_deleg_t *deleg_v)
+{
+	deleg_v->obj = NULL;
+	deleg_v->sym = NULL;
+	rdata_deleg_delete(deleg_v);
+}
+
+/** Destroy enum.
+ *
+ * @param enum_v		Reference
+ */
+static void rdata_enum_destroy(rdata_enum_t *enum_v)
+{
+	enum_v->value = NULL;
+	rdata_enum_delete(enum_v);
+}
+
+/** Destroy array.
+ *
+ * @param array_v		Array
+ */
+static void rdata_array_destroy(rdata_array_t *array_v)
+{
+	int d;
+	size_t n_elems, p;
+
+	/*
+	 * Compute total number of elements in array.
+	 * At the same time zero out the extent array.
+	 */
+	n_elems = 1;
+	for (d = 0; d < array_v->rank; d++) {
+		n_elems = n_elems * array_v->extent[d];
+		array_v->extent[d] = 0;
+	}
+
+	/* Destroy all elements and zero out the array */
+	for (p = 0; p < n_elems; p++) {
+		rdata_var_delete(array_v->element[p]);
+		array_v->element[p] = NULL;
+	}
+
+	/* Free the arrays */
+	free(array_v->element);
+	free(array_v->extent);
+
+	array_v->rank = 0;
+
+	/* Deallocate the node */
+	rdata_array_delete(array_v);
+}
+
+/** Destroy object.
+ *
+ * @param object_v		Object
+ */
+static void rdata_object_destroy(rdata_object_t *object_v)
+{
+	/* XXX TODO */
+	rdata_object_delete(object_v);
+}
+
+/** Destroy resource.
+ *
+ * @param resource_v		Resource
+ */
+static void rdata_resource_destroy(rdata_resource_t *resource_v)
+{
+	/*
+	 * XXX Presumably this should be handled by the appropriate
+	 * built-in module, so, some call-back function would be required.
+	 */
+	resource_v->data = NULL;
+	rdata_resource_delete(resource_v);
+}
+
+/** Destroy symbol.
+ *
+ * @param symbol_v		Symbol
+ */
+static void rdata_symbol_destroy(rdata_symbol_t *symbol_v)
+{
+	symbol_v->sym = NULL;
+	rdata_symbol_delete(symbol_v);
 }
 
@@ -671,27 +1249,9 @@
 void rdata_var_write(rdata_var_t *var, rdata_value_t *value)
 {
-	rdata_var_t *nvar;
+	/* Free old content of var->u */
+	rdata_var_destroy_inner(var);
 
 	/* Perform a shallow copy of @c value->var. */
-	rdata_var_copy(value->var, &nvar);
-
-	/* XXX do this in a prettier way. */
-
-	var->vc = nvar->vc;
-	switch (nvar->vc) {
-	case vc_bool: var->u.bool_v = nvar->u.bool_v; break;
-	case vc_char: var->u.char_v = nvar->u.char_v; break;
-	case vc_int: var->u.int_v = nvar->u.int_v; break;
-	case vc_string: var->u.string_v = nvar->u.string_v; break;
-	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;
-	}
-
-	/* XXX We should free some stuff around here. */
+	rdata_var_copy_to(value->var, var);
 }
 
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/rdata.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -41,4 +41,5 @@
 
 rdata_var_t *rdata_var_new(var_class_t vc);
+void rdata_var_delete(rdata_var_t *var);
 rdata_ref_t *rdata_ref_new(void);
 rdata_deleg_t *rdata_deleg_new(void);
@@ -53,6 +54,37 @@
 rdata_symbol_t *rdata_symbol_new(void);
 
+void rdata_address_delete(rdata_address_t *address);
+void rdata_value_delete(rdata_value_t *value);
+void rdata_var_delete(rdata_var_t *var);
+void rdata_item_delete(rdata_item_t *item);
+void rdata_addr_var_delete(rdata_addr_var_t *addr_var);
+void rdata_addr_prop_delete(rdata_addr_prop_t *addr_prop);
+void rdata_aprop_named_delete(rdata_aprop_named_t *aprop_named);
+void rdata_aprop_indexed_delete(rdata_aprop_indexed_t *aprop_indexed);
+
+void rdata_bool_delete(rdata_bool_t *bool_v);
+void rdata_char_delete(rdata_char_t *char_v);
+void rdata_int_delete(rdata_int_t *int_v);
+void rdata_string_delete(rdata_string_t *string_v);
+void rdata_ref_delete(rdata_ref_t *ref_v);
+void rdata_deleg_delete(rdata_deleg_t *deleg_v);
+void rdata_enum_delete(rdata_enum_t *enum_v);
+void rdata_array_delete(rdata_array_t *array_v);
+void rdata_object_delete(rdata_object_t *object_v);
+void rdata_resource_delete(rdata_resource_t *resource_v);
+void rdata_symbol_delete(rdata_symbol_t *symbol_v);
+
 void rdata_array_alloc_element(rdata_array_t *array);
+void rdata_value_copy(rdata_value_t *val, rdata_value_t **rval);
 void rdata_var_copy(rdata_var_t *src, rdata_var_t **dest);
+
+void rdata_address_destroy(rdata_address_t *address);
+void rdata_addr_var_destroy(rdata_addr_var_t *addr_var);
+void rdata_addr_prop_destroy(rdata_addr_prop_t *addr_prop);
+void rdata_aprop_named_destroy(rdata_aprop_named_t *aprop_named);
+void rdata_aprop_indexed_destroy(rdata_aprop_indexed_t *aprop_indexed);
+void rdata_value_destroy(rdata_value_t *value);
+void rdata_var_destroy(rdata_var_t *var);
+void rdata_item_destroy(rdata_item_t *item);
 
 void rdata_var_read(rdata_var_t *var, rdata_item_t **ritem);
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/rdata_t.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -272,6 +272,9 @@
 typedef struct rdata_value {
 	/**
-	 * Read-only Variable holding a copy of the data. The same @c var
-	 * can be shared between different instances of @c rdata_value_t.
+	 * Read-only Variable holding a copy of the data. Currently we don't
+	 * allow sharing the same @c var node between different value nodes
+	 * so that when destroying the value we can destroy the var.
+	 *
+	 * We could share this, but would need to reference-count it.
 	 */
 	rdata_var_t *var;
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/run.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -53,4 +53,5 @@
 static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
 static void run_if(run_t *run, stree_if_t *if_s);
+static void run_switch(run_t *run, stree_switch_t *switch_s);
 static void run_while(run_t *run, stree_while_t *while_s);
 static void run_raise(run_t *run, stree_raise_t *raise_s);
@@ -142,4 +143,5 @@
 	run_proc_ar_set_args(run, proc_ar, &main_args);
 	run_proc(run, proc_ar, &res);
+	run_proc_ar_destroy(run, proc_ar);
 
 	run_exc_check_unhandled(run);
@@ -272,4 +274,7 @@
 	assert(list_node_data(node, run_block_ar_t *) == block_ar);
 	list_remove(&proc_ar->block_ar, node);
+
+	/* Deallocate block activation record. */
+	run_block_ar_destroy(run, block_ar);
 }
 
@@ -303,4 +308,7 @@
 		run_if(run, stat->u.if_s);
 		break;
+	case st_switch:
+		run_switch(run, stat->u.switch_s);
+		break;
 	case st_while:
 		run_while(run, stat->u.while_s);
@@ -342,4 +350,9 @@
 	run_expr(run, exps->expr, &rexpr);
 
+	/*
+	 * If the expression has a value, the caller should have asked for it.
+	 */
+	assert(res != NULL || rexpr == NULL);
+
 	if (res != NULL)
 		*res = rexpr;
@@ -355,15 +368,10 @@
 	run_block_ar_t *block_ar;
 	rdata_var_t *var, *old_var;
-	tdata_item_t *var_ti;
 
 #ifdef DEBUG_RUN_TRACE
 	printf("Executing variable declaration statement.\n");
 #endif
-	/* Compute variable type. XXX Memoize. */
-	run_texpr(run->program, run_get_current_csi(run), vdecl->type,
-	    &var_ti);
-
 	/* Create variable and initialize with default value. */
-	run_var_new(run, var_ti, &var);
+	run_var_new(run, vdecl->titem, &var);
 
 	block_ar = run_get_current_block_ar(run);
@@ -393,5 +401,5 @@
 	list_node_t *ifc_node;
 	stree_if_clause_t *ifc;
-	bool_t clause_fired;
+	bool_t rcond_b, clause_fired;
 
 #ifdef DEBUG_RUN_TRACE
@@ -411,5 +419,8 @@
 			return;
 
-		if (run_item_boolean_value(run, rcond) == b_true) {
+		rcond_b = run_item_boolean_value(run, rcond);
+		rdata_item_destroy(rcond);
+
+		if (rcond_b == b_true) {
 #ifdef DEBUG_RUN_TRACE
 			printf("Taking non-default path.\n");
@@ -436,4 +447,106 @@
 }
 
+/** Run @c switch statement.
+ *
+ * @param run		Runner object
+ * @param switch_s	Switch statement to run
+ */
+static void run_switch(run_t *run, stree_switch_t *switch_s)
+{
+	rdata_item_t *rsexpr, *rsexpr_vi;
+	rdata_item_t *rwexpr, *rwexpr_vi;
+	list_node_t *whenc_node;
+	stree_when_t *whenc;
+	list_node_t *expr_node;
+	stree_expr_t *expr;
+	bool_t clause_fired;
+	bool_t equal;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Executing switch statement.\n");
+#endif
+	rsexpr_vi = NULL;
+
+	/* Evaluate switch expression */
+	run_expr(run, switch_s->expr, &rsexpr);
+	if (run_is_bo(run))
+		goto cleanup;
+
+	/* Convert to value item */
+	run_cvt_value_item(run, rsexpr, &rsexpr_vi);
+	rdata_item_destroy(rsexpr);
+	if (run_is_bo(run))
+		goto cleanup;
+
+	clause_fired = b_false;
+	whenc_node = list_first(&switch_s->when_clauses);
+
+	/* Walk through all when clauses and see if they fire. */
+
+	while (whenc_node != NULL) {
+		/* Get when clause */
+		whenc = list_node_data(whenc_node, stree_when_t *);
+
+		expr_node = list_first(&whenc->exprs);
+
+		/* Walk through all expressions in the when clause */
+		while (expr_node != NULL) {
+			/* Get expression */
+			expr = list_node_data(expr_node, stree_expr_t *);
+
+			/* Evaluate expression */
+			run_expr(run, expr, &rwexpr);
+			if (run_is_bo(run))
+				goto cleanup;
+
+			/* Convert to value item */
+			run_cvt_value_item(run, rwexpr, &rwexpr_vi);
+			rdata_item_destroy(rwexpr);
+			if (run_is_bo(run)) {
+				rdata_item_destroy(rwexpr_vi);
+				goto cleanup;
+			}
+
+			/* Check if values are equal ('==') */
+			run_equal(run, rsexpr_vi->u.value,
+			    rwexpr_vi->u.value, &equal);
+			rdata_item_destroy(rwexpr_vi);
+			if (run_is_bo(run))
+				goto cleanup;
+
+			if (equal) {
+#ifdef DEBUG_RUN_TRACE
+				printf("Taking non-default path.\n");
+#endif
+				run_block(run, whenc->block);
+				clause_fired = b_true;
+				break;
+			}
+
+			expr_node = list_next(&whenc->exprs, expr_node);
+		}
+
+		if (clause_fired)
+			break;
+
+		whenc_node = list_next(&switch_s->when_clauses, whenc_node);
+	}
+
+	/* If no when clause fired, invoke the else clause. */
+	if (clause_fired == b_false && switch_s->else_block != NULL) {
+#ifdef DEBUG_RUN_TRACE
+		printf("Taking default path.\n");
+#endif
+		run_block(run, switch_s->else_block);
+	}
+cleanup:
+	if (rsexpr_vi != NULL)
+		rdata_item_destroy(rsexpr_vi);
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Switch statement terminated.\n");
+#endif
+}
+
 /** Run @c while statement.
  *
@@ -453,4 +566,5 @@
 
 	while (run_item_boolean_value(run, rcond) == b_true) {
+		rdata_item_destroy(rcond);
 		run_block(run, while_s->body);
 		run_expr(run, while_s->cond, &rcond);
@@ -459,4 +573,7 @@
 	}
 
+	if (rcond != NULL)
+		rdata_item_destroy(rcond);
+
 	if (run->thread_ar->bo_mode == bm_stat) {
 		/* Bailout due to break statement */
@@ -487,4 +604,7 @@
 
 	run_cvt_value_item(run, rexpr, &rexpr_vi);
+	rdata_item_destroy(rexpr);
+	if (run_is_bo(run))
+		return;
 
 	/* Store expression cspan in thread AR. */
@@ -492,4 +612,5 @@
 
 	/* Store expression result in thread AR. */
+	/* XXX rexpr_vi is leaked here, we only return ->u.value */
 	run->thread_ar->exc_payload = rexpr_vi->u.value;
 
@@ -541,4 +662,7 @@
 
 		run_cvt_value_item(run, rexpr, &rexpr_vi);
+		rdata_item_destroy(rexpr);
+		if (run_is_bo(run))
+			return;
 
 		/* Store expression result in procedure AR. */
@@ -632,16 +756,11 @@
 {
 	stree_csi_t *exc_csi;
-	tdata_item_t *etype;
 
 	/* Get CSI of active exception. */
 	exc_csi = run_exc_payload_get_csi(run);
 
-	/* Evaluate type expression in except clause. */
-	run_texpr(run->program, run_get_current_csi(run), except_c->etype,
-	    &etype);
-
 	/* Determine if active exc. is derived from type in exc. clause. */
 	/* XXX This is wrong, it does not work with generics. */
-	return tdata_is_csi_derived_from_ti(exc_csi, etype);
+	return tdata_is_csi_derived_from_ti(exc_csi, except_c->titem);
 }
 
@@ -1009,5 +1128,5 @@
 	(void) run;
 
-	/* Create function activation record. */
+	/* Create procedure activation record. */
 	proc_ar = run_proc_ar_new();
 	proc_ar->obj = obj;
@@ -1024,4 +1143,31 @@
 	*rproc_ar = proc_ar;
 }
+
+/** Destroy a procedure AR.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Pointer to procedure activation record
+ */
+void run_proc_ar_destroy(run_t *run, run_proc_ar_t *proc_ar)
+{
+	list_node_t *ar_node;
+	run_block_ar_t *block_ar;
+
+	(void) run;
+
+	/* Destroy special block activation record. */
+	ar_node = list_first(&proc_ar->block_ar);
+	block_ar = list_node_data(ar_node, run_block_ar_t *);
+	list_remove(&proc_ar->block_ar, ar_node);
+	run_block_ar_destroy(run, block_ar);
+
+	/* Destroy procedure activation record. */
+	proc_ar->obj = NULL;
+	proc_ar->proc = NULL;
+	list_fini(&proc_ar->block_ar);
+	proc_ar->retval = NULL;
+	run_proc_ar_delete(proc_ar);
+}
+
 
 /** Fill arguments in a procedure AR.
@@ -1055,4 +1201,5 @@
 	rdata_ref_t *ref;
 	rdata_array_t *array;
+	rdata_var_t *elem_var;
 	int n_vargs, idx;
 
@@ -1147,5 +1294,6 @@
 			assert(rarg->ic == ic_value);
 
-			rdata_var_write(array->element[idx], rarg->u.value);
+			run_value_item_to_var(rarg, &elem_var);
+			array->element[idx] = elem_var;
 
 			rarg_n = list_next(arg_vals, rarg_n);
@@ -1241,4 +1389,34 @@
 }
 
+/** Destroy a block AR.
+ *
+ * @param run		Runner object
+ * @param proc_ar	Pointer to block activation record
+ */
+void run_block_ar_destroy(run_t *run, run_block_ar_t *block_ar)
+{
+	map_elem_t *elem;
+	rdata_var_t *var;
+	int key;
+
+	(void) run;
+
+	elem = intmap_first(&block_ar->vars);
+	while (elem != NULL) {
+		/* Destroy the variable */
+		var = intmap_elem_get_value(elem);
+		rdata_var_destroy(var);
+
+		/* Remove the map element */
+		key = intmap_elem_get_key(elem);
+		intmap_set(&block_ar->vars, key, NULL);
+
+		elem = intmap_first(&block_ar->vars);
+	}
+
+	intmap_fini(&block_ar->vars);
+	run_block_ar_delete(block_ar);
+}
+
 /** Convert item to value item.
  *
@@ -1269,7 +1447,7 @@
 	}
 
-	/* It already is a value, we can share the @c var. */
+	/* Make a copy of the var node within. */
 	value = rdata_value_new();
-	value->var = item->u.value->var;
+	rdata_var_copy(item->u.value->var, &value->var);
 	*ritem = rdata_item_new(ic_value);
 	(*ritem)->u.value = value;
@@ -1358,4 +1536,5 @@
 {
 	(void) run;
+	assert(ritem != NULL);
 
 	switch (address->ac) {
@@ -1368,5 +1547,5 @@
 	}
 
-	assert((*ritem)->ic == ic_value);
+	assert(*ritem == NULL || (*ritem)->ic == ic_value);
 }
 
@@ -1457,4 +1636,7 @@
 	run_proc(run, proc_ar, ritem);
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Getter returns ");
@@ -1529,4 +1711,7 @@
 	/* Setter should not return a value. */
 	assert(ritem == NULL);
+
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
 
 #ifdef DEBUG_RUN_TRACE
@@ -1590,4 +1775,9 @@
 #endif
 	run_cvt_value_item(run, ref, &ref_val);
+	if (run_is_bo(run)) {
+		*ritem = run_recovery_item(run);
+		return;
+	}
+
 	assert(ref_val->u.value->var->vc == vc_ref);
 
@@ -1598,4 +1788,6 @@
 	address->u.var_a = addr_var;
 	addr_var->vref = ref_val->u.value->var->u.ref_v->vref;
+
+	rdata_item_destroy(ref_val);
 
 	if (addr_var->vref == NULL) {
@@ -1840,7 +2032,6 @@
 }
 
-/** Construct a new procedure activation record.
- *
- * @param run	Runner object
+/** Allocate a new procedure activation record.
+ *
  * @return	New procedure AR.
  */
@@ -1858,5 +2049,15 @@
 }
 
-/** Construct a new block activation record.
+/** Deallocate a procedure activation record.
+ *
+ * @return	New procedure AR.
+ */
+void run_proc_ar_delete(run_proc_ar_t *proc_ar)
+{
+	assert(proc_ar != NULL);
+	free(proc_ar);
+}
+
+/** Allocate a new block activation record.
  *
  * @param run	Runner object
@@ -1875,2 +2076,13 @@
 	return block_ar;
 }
+
+/** Deallocate a new block activation record.
+ *
+ * @param run	Runner object
+ * @return	New block AR.
+ */
+void run_block_ar_delete(run_block_ar_t *block_ar)
+{
+	assert(block_ar != NULL);
+	free(block_ar);
+}
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/run.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -61,4 +61,5 @@
 void run_proc_ar_create(run_t *run, rdata_var_t *obj, stree_proc_t *proc,
     run_proc_ar_t **rproc_ar);
+void run_proc_ar_destroy(run_t *run, run_proc_ar_t *proc_ar);
 
 var_class_t run_item_get_vc(run_t *run, rdata_item_t *item);
@@ -79,5 +80,10 @@
 run_thread_ar_t *run_thread_ar_new(void);
 run_proc_ar_t *run_proc_ar_new(void);
+void run_proc_ar_delete(run_proc_ar_t *proc_ar);
 run_block_ar_t *run_block_ar_new(void);
+void run_block_ar_delete(run_block_ar_t *block_ar);
+void run_proc_ar_delete(run_proc_ar_t *proc_ar);
+void run_block_ar_destroy(run_t *run, run_block_ar_t *block_ar);
+
 
 #endif
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/run_expr.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -113,4 +113,5 @@
 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_destroy_arg_vals(list_t *arg_vals);
 
 static void run_index(run_t *run, stree_index_t *index, rdata_item_t **res);
@@ -200,4 +201,7 @@
 	rdata_address_t *address;
 	rdata_addr_var_t *addr_var;
+	rdata_addr_prop_t *addr_prop;
+	rdata_aprop_named_t *aprop_named;
+	rdata_deleg_t *deleg_p;
 	rdata_value_t *value;
 	rdata_var_t *var;
@@ -334,13 +338,17 @@
 		break;
 	case sc_var:
-#ifdef DEBUG_RUN_TRACE
-		printf("Referencing member variable.\n");
-#endif
-		/* There should be no global variables. */
+	case sc_prop:
+#ifdef DEBUG_RUN_TRACE
+		if (sym->sc == sc_var)
+			printf("Referencing member variable.\n");
+		else
+			printf("Referencing unqualified property.\n");
+#endif
+		/* There should be no global variables or properties. */
 		assert(csi != NULL);
 
 		if (symbol_search_csi(run->program, csi, nameref->name)
 		    == NULL && !stree_symbol_is_static(sym)) {
-			/* Variable is not in the current object. */
+			/* Symbol is not in the current object. */
 			printf("Error: Cannot access non-static member "
 			    "variable '");
@@ -352,6 +360,10 @@
 		}
 
+		/*
+		 * Determine object in which the symbol resides
+		 */
 		if (stree_symbol_is_static(sym)) {
 			/*
+			 * Class object
 			 * XXX This is too slow!
 			 *
@@ -365,26 +377,46 @@
 			aobj = sobj->u.object_v;
 		} else {
-			aobj = obj;
+			/*
+			 * Instance object. Currently we don't support
+			 * true inner classes, thus we know the symbol is
+			 * in the active object (there is no dynamic parent).
+			 */
+			sobj = proc_ar->obj;
+			aobj = sobj->u.object_v;;
 		}
 
-		/* Find member variable in object. */
-		member_var = intmap_get(&aobj->fields, nameref->name->sid);
-		assert(member_var != NULL);
-
-		/* Return address of the variable. */
-		item = rdata_item_new(ic_address);
-		address = rdata_address_new(ac_var);
-		addr_var = rdata_addr_var_new();
-
-		item->u.address = address;
-		address->u.var_a = addr_var;
-		addr_var->vref = member_var;
-
-		*res = item;
-		break;
-	case sc_prop:
-		/* XXX TODO */
-		printf("Unimplemented: Property name reference.\n");
-		abort();
+		if (sym->sc == sc_var) {
+			/* Find member variable in object. */
+			member_var = intmap_get(&aobj->fields,
+			    nameref->name->sid);
+			assert(member_var != NULL);
+
+			/* Return address of the variable. */
+			item = rdata_item_new(ic_address);
+			address = rdata_address_new(ac_var);
+			addr_var = rdata_addr_var_new();
+
+			item->u.address = address;
+			address->u.var_a = addr_var;
+			addr_var->vref = member_var;
+
+			*res = item;
+		} else {
+			/* Construct named property address. */
+			item = rdata_item_new(ic_address);
+			address = rdata_address_new(ac_prop);
+			addr_prop = rdata_addr_prop_new(apc_named);
+			aprop_named = rdata_aprop_named_new();
+			item->u.address = address;
+			address->u.prop_a = addr_prop;
+			addr_prop->u.named = aprop_named;
+
+			deleg_p = rdata_deleg_new();
+			deleg_p->obj = sobj;
+			deleg_p->sym = sym;
+			addr_prop->u.named->prop_d = deleg_p;
+
+			*res = item;
+		}
 		break;
 	}
@@ -611,4 +643,9 @@
 	rdata_value_t *v1, *v2;
 
+	rarg1_i = NULL;
+	rarg2_i = NULL;
+	rarg1_vi = NULL;
+	rarg2_vi = NULL;
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Run binary operation.\n");
@@ -616,20 +653,31 @@
 	run_expr(run, binop->arg1, &rarg1_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check binop argument result.\n");
+#endif
+	run_cvt_value_item(run, rarg1_i, &rarg1_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_expr(run, binop->arg2, &rarg2_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
-	}
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Check binop argument results.\n");
-#endif
-
-	run_cvt_value_item(run, rarg1_i, &rarg1_vi);
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Check binop argument result.\n");
+#endif
 	run_cvt_value_item(run, rarg2_i, &rarg2_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
 
 	v1 = rarg1_vi->u.value;
@@ -668,4 +716,14 @@
 		assert(b_false);
 	}
+
+cleanup:
+	if (rarg1_i != NULL)
+		rdata_item_destroy(rarg1_i);
+	if (rarg2_i != NULL)
+		rdata_item_destroy(rarg2_i);
+	if (rarg1_vi != NULL)
+		rdata_item_destroy(rarg1_vi);
+	if (rarg2_vi != NULL)
+		rdata_item_destroy(rarg2_vi);
 }
 
@@ -1054,5 +1112,5 @@
 	rdata_bool_t *bool_v;
 
-	rdata_var_t *ref1, *ref2;
+	stree_embr_t *e1, *e2;
 
 	(void) run;
@@ -1067,13 +1125,13 @@
 	var->u.bool_v = bool_v;
 
-	ref1 = v1->var->u.ref_v->vref;
-	ref2 = v2->var->u.ref_v->vref;
+	e1 = v1->var->u.enum_v->value;
+	e2 = v2->var->u.enum_v->value;
 
 	switch (binop->bc) {
 	case bo_equal:
-		bool_v->value = (ref1 == ref2);
+		bool_v->value = (e1 == e2);
 		break;
 	case bo_notequal:
-		bool_v->value = (ref1 != ref2);
+		bool_v->value = (e1 != e2);
 		break;
 	default:
@@ -1100,8 +1158,11 @@
 	printf("Run unary operation.\n");
 #endif
+	rarg_i = NULL;
+	rarg_vi = NULL;
+
 	run_expr(run, unop->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
@@ -1110,4 +1171,8 @@
 #endif
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
 
 	val = rarg_vi->u.value;
@@ -1124,7 +1189,12 @@
 		    "type %d.\n", val->var->vc);
 		run_raise_error(run);
-		*res = NULL;
-		break;
-	}
+		*res = run_recovery_item(run);
+		break;
+	}
+cleanup:
+	if (rarg_i != NULL)
+		rdata_item_destroy(rarg_i);
+	if (rarg_vi != NULL)
+		rdata_item_destroy(rarg_vi);
 }
 
@@ -1208,4 +1278,77 @@
 	*res = item;
 }
+
+/** Run equality comparison of two values
+ *
+ * This should be equivalent to equality ('==') binary operation.
+ * XXX Duplicating code of run_binop_xxx().
+ *
+ * @param run		Runner object
+ * @param v1		Value of first argument
+ * @param v2		Value of second argument
+ * @param res		Place to store result (plain boolean value)
+ */
+void run_equal(run_t *run, rdata_value_t *v1, rdata_value_t *v2, bool_t *res)
+{
+	bool_t b1, b2;
+	bigint_t *c1, *c2;
+	bigint_t *i1, *i2;
+	bigint_t diff;
+	const char *s1, *s2;
+	rdata_var_t *ref1, *ref2;
+	stree_embr_t *e1, *e2;
+
+	(void) run;
+	assert(v1->var->vc == v2->var->vc);
+
+	switch (v1->var->vc) {
+	case vc_bool:
+		b1 = v1->var->u.bool_v->value;
+		b2 = v2->var->u.bool_v->value;
+
+		*res = (b1 == b2);
+		break;
+	case vc_char:
+		c1 = &v1->var->u.char_v->value;
+		c2 = &v2->var->u.char_v->value;
+
+    		bigint_sub(c1, c2, &diff);
+		*res = bigint_is_zero(&diff);
+		break;
+	case vc_int:
+		i1 = &v1->var->u.int_v->value;
+		i2 = &v2->var->u.int_v->value;
+
+		bigint_sub(i1, i2, &diff);
+		*res = bigint_is_zero(&diff);
+		break;
+	case vc_string:
+		s1 = v1->var->u.string_v->value;
+		s2 = v2->var->u.string_v->value;
+
+		*res = os_str_cmp(s1, s2) == 0;
+		break;
+	case vc_ref:
+		ref1 = v1->var->u.ref_v->vref;
+		ref2 = v2->var->u.ref_v->vref;
+
+		*res = (ref1 == ref2);
+		break;
+	case vc_enum:
+		e1 = v1->var->u.enum_v->value;
+		e2 = v2->var->u.enum_v->value;
+
+		*res = (e1 == e2);
+		break;
+
+	case vc_deleg:
+	case vc_array:
+	case vc_object:
+	case vc_resource:
+	case vc_symbol:
+		assert(b_false);
+	}
+}
+
 
 /** Evaluate @c new operation.
@@ -1297,9 +1440,14 @@
 		run_expr(run, expr, &rexpr);
 		if (run_is_bo(run)) {
-			*res = NULL;
+			*res = run_recovery_item(run);
 			return;
 		}
 
 		run_cvt_value_item(run, rexpr, &rexpr_vi);
+		if (run_is_bo(run)) {
+			*res = run_recovery_item(run);
+			return;
+		}
+
 		assert(rexpr_vi->ic == ic_value);
 		rexpr_var = rexpr_vi->u.value->var;
@@ -1375,5 +1523,5 @@
 	run_call_args(run, &new_op->ctor_args, &arg_vals);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -1387,4 +1535,8 @@
 	assert(obj_i->u.address->ac == ac_var);
 	run_object_ctor(run, obj_i->u.address->u.var_a->vref, &arg_vals);
+	rdata_item_destroy(obj_i);
+
+	/* Destroy argument values */
+	run_destroy_arg_vals(&arg_vals);
 }
 
@@ -1404,8 +1556,10 @@
 	printf("Run access operation.\n");
 #endif
+	rarg = NULL;
+
 	run_expr(run, access->arg, &rarg);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
     	}
 
@@ -1416,4 +1570,7 @@
 
 	run_access_item(run, access, rarg, res);
+cleanup:
+	if (rarg != NULL)
+		rdata_item_destroy(rarg);
 }
 
@@ -1484,4 +1641,7 @@
 	/* Try again. */
 	run_access_item(run, access, darg, res);
+
+	/* Destroy temporary */
+	rdata_item_destroy(darg);
 }
 
@@ -1790,4 +1950,9 @@
 #endif
 	run_cvt_value_item(run, arg, &arg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	arg_val = arg_vi->u.value;
 	assert(arg_val->var->vc == vc_symbol);
@@ -1800,4 +1965,6 @@
 	embr = stree_enum_find_mbr(symbol_v->sym->u.enum_d,
 	    access->member_name);
+
+	rdata_item_destroy(arg_vi);
 
 	/* Member existence should be ensured by static type checking. */
@@ -1841,16 +2008,19 @@
 	printf("Run call operation.\n");
 #endif
+	rdeleg = NULL;
+	rdeleg_vi = NULL;
+
 	run_expr(run, call->fun, &rdeleg);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
-	}
-
-	if (run->thread_ar->bo_mode != bm_none) {
 		*res = run_recovery_item(run);
-		return;
+		goto cleanup;
 	}
 
 	run_cvt_value_item(run, rdeleg, &rdeleg_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
 	assert(rdeleg_vi->ic == ic_value);
 
@@ -1877,6 +2047,6 @@
 	run_call_args(run, &call->args, &arg_vals);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
@@ -1889,4 +2059,7 @@
 	/* Fill in argument values. */
 	run_proc_ar_set_args(run, proc_ar, &arg_vals);
+
+	/* Destroy arg_vals, they are no longer needed. */
+	run_destroy_arg_vals(&arg_vals);
 
 	/* Run the function. */
@@ -1900,4 +2073,13 @@
 	}
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
+cleanup:
+	if (rdeleg != NULL)
+		rdata_item_destroy(rdeleg);
+	if (rdeleg_vi != NULL)
+		rdata_item_destroy(rdeleg_vi);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Returned from function call.\n");
@@ -1928,11 +2110,51 @@
 		run_expr(run, arg, &rarg_i);
 		if (run_is_bo(run))
-			return;
+			goto error;
 
 		run_cvt_value_item(run, rarg_i, &rarg_vi);
+		rdata_item_destroy(rarg_i);
+		if (run_is_bo(run))
+			goto error;
 
 		list_append(arg_vals, rarg_vi);
 		arg_n = list_next(args, arg_n);
 	}
+	return;
+
+error:
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	run_destroy_arg_vals(arg_vals);
+}
+
+/** Destroy list of evaluated arguments.
+ *
+ * Provided a list of evaluated arguments, destroy them, removing them
+ * from the list and fini the list itself.
+ *
+ * @param arg_vals	List of evaluated arguments (value items,
+ *			rdata_item_t).
+ */
+static void run_destroy_arg_vals(list_t *arg_vals)
+{
+	list_node_t *val_n;
+	rdata_item_t *val_i;
+
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	while (!list_is_empty(arg_vals)) {
+		val_n = list_first(arg_vals);
+		val_i = list_node_data(val_n, rdata_item_t *);
+
+		rdata_item_destroy(val_i);
+		list_remove(arg_vals, val_n);
+	}
+	list_fini(arg_vals);
 }
 
@@ -1954,4 +2176,6 @@
 	var_class_t vc;
 	list_t arg_vals;
+	list_node_t *val_n;
+	rdata_item_t *val_i;
 
 #ifdef DEBUG_RUN_TRACE
@@ -1960,5 +2184,5 @@
 	run_expr(run, index->base, &rbase);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -1969,6 +2193,7 @@
 	if (vc == vc_ref) {
 		run_dereference(run, rbase, index->base->cspan, &base_i);
+		rdata_item_destroy(rbase);
 		if (run_is_bo(run)) {
-			*res = NULL;
+			*res = run_recovery_item(run);
 			return;
 		}
@@ -1987,9 +2212,14 @@
 		run_expr(run, arg, &rarg_i);
 		if (run_is_bo(run)) {
-			*res = NULL;
-			return;
+			*res = run_recovery_item(run);
+			goto cleanup;
 		}
 
 		run_cvt_value_item(run, rarg_i, &rarg_vi);
+		rdata_item_destroy(rarg_i);
+		if (run_is_bo(run)) {
+			*res = run_recovery_item(run);
+			goto cleanup;
+		}
 
 		list_append(&arg_vals, rarg_vi);
@@ -2012,4 +2242,22 @@
 		exit(1);
 	}
+
+	/* Destroy the indexing base temporary */
+	rdata_item_destroy(base_i);
+cleanup:
+	/*
+	 * An exception or error occured while evaluating one of the
+	 * arguments. Destroy already obtained argument values and
+	 * dismantle the list.
+	 */
+	while (!list_is_empty(&arg_vals)) {
+		val_n = list_first(&arg_vals);
+		val_i = list_node_data(val_n, rdata_item_t *);
+
+		rdata_item_destroy(val_i);
+		list_remove(&arg_vals, val_n);
+	}
+
+	list_fini(&arg_vals);
 }
 
@@ -2136,5 +2384,5 @@
 
 	list_node_t *node;
-	rdata_item_t *arg;
+	rdata_item_t *arg, *arg_copy;
 
 #ifdef DEBUG_RUN_TRACE
@@ -2186,5 +2434,14 @@
 	while (node != NULL) {
 		arg = list_node_data(node, rdata_item_t *);
-		list_append(&aprop_indexed->args, arg);
+
+		/*
+		 * Clone argument so that original can
+		 * be freed.
+		 */
+		assert(arg->ic == ic_value);
+		arg_copy = rdata_item_new(ic_value);
+		rdata_value_copy(arg->u.value, &arg_copy->u.value);
+
+		list_append(&aprop_indexed->args, arg_copy);
 		node = list_next(args, node);
 	}
@@ -2225,4 +2482,9 @@
 
 	run_cvt_value_item(run, base, &base_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(base_vi->u.value->var->vc == vc_string);
 	string = base_vi->u.value->var->u.string_v;
@@ -2277,5 +2539,5 @@
 		    index->expr->cspan);
 		*res = run_recovery_item(run);
-		return;
+		goto cleanup;
 	}
 
@@ -2291,4 +2553,6 @@
 
 	*res = ritem;
+cleanup:
+	rdata_item_destroy(base_vi);
 }
 
@@ -2310,17 +2574,26 @@
 	printf("Run assign operation.\n");
 #endif
+	rdest_i = NULL;
+	rsrc_i = NULL;
+	rsrc_vi = NULL;
+
 	run_expr(run, assign->dest, &rdest_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_expr(run, assign->src, &rsrc_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
-		return;
+		*res = run_recovery_item(run);
+		goto cleanup;
 	}
 
 	run_cvt_value_item(run, rsrc_i, &rsrc_vi);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		goto cleanup;
+	}
+
 	assert(rsrc_vi->ic == ic_value);
 
@@ -2334,4 +2607,11 @@
 
 	*res = NULL;
+cleanup:
+	if (rdest_i != NULL)
+		rdata_item_destroy(rdest_i);
+	if (rsrc_i != NULL)
+		rdata_item_destroy(rsrc_i);
+	if (rsrc_vi != NULL)
+		rdata_item_destroy(rsrc_vi);
 }
 
@@ -2359,5 +2639,5 @@
 	run_expr(run, as_op->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
@@ -2369,4 +2649,11 @@
 	assert(run_item_get_vc(run, rarg_i) == vc_ref);
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	rdata_item_destroy(rarg_i);
+
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(rarg_vi->ic == ic_value);
 
@@ -2405,4 +2692,7 @@
 	}
 
+	/* The dereferenced item is not used anymore. */
+	rdata_item_destroy(rarg_di);
+
 	*res = rarg_vi;
 }
@@ -2435,9 +2725,15 @@
 	run_expr(run, box->arg, &rarg_i);
 	if (run_is_bo(run)) {
-		*res = NULL;
+		*res = run_recovery_item(run);
 		return;
 	}
 
 	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	rdata_item_destroy(rarg_i);
+	if (run_is_bo(run)) {
+		*res = run_recovery_item(run);
+		return;
+	}
+
 	assert(rarg_vi->ic == ic_value);
 
@@ -2482,4 +2778,5 @@
 
 	rdata_var_write(mbr_var, rarg_vi->u.value);
+	rdata_item_destroy(rarg_vi);
 }
 
@@ -2657,4 +2954,7 @@
 	assert(res == NULL);
 
+	/* Destroy procedure activation record. */
+	run_proc_ar_destroy(run, proc_ar);
+
 #ifdef DEBUG_RUN_TRACE
 	printf("Returned from constructor..\n");
@@ -2675,7 +2975,10 @@
 	rdata_item_t *vitem;
 	rdata_var_t *var;
+	bool_t res;
 
 	(void) run;
 	run_cvt_value_item(run, item, &vitem);
+	if (run_is_bo(run))
+		return b_true;
 
 	assert(vitem->ic == ic_value);
@@ -2683,4 +2986,8 @@
 
 	assert(var->vc == vc_bool);
-	return var->u.bool_v->value;
-}
+	res = var->u.bool_v->value;
+
+	/* Free value item */
+	rdata_item_destroy(vitem);
+	return res;
+}
Index: uspace/app/sbi/src/run_expr.h
===================================================================
--- uspace/app/sbi/src/run_expr.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/run_expr.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,4 +39,5 @@
     rdata_var_t **res);
 
+void run_equal(run_t *run, rdata_value_t *v1, rdata_value_t *v2, bool_t *res);
 bool_t run_item_boolean_value(run_t *run, rdata_item_t *item);
 
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/stree.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -397,4 +397,21 @@
 }
 
+/** Allocate new @c switch statement.
+ *
+ * @return	New @c if statement
+ */
+stree_switch_t *stree_switch_new(void)
+{
+	stree_switch_t *switch_s;
+
+	switch_s = calloc(1, sizeof(stree_switch_t));
+	if (switch_s == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return switch_s;
+}
+
 /** Allocate new @c while statement.
  *
@@ -548,4 +565,21 @@
 
 	return if_clause;
+}
+
+/** Allocate new @c when clause.
+ *
+ * @return	New @c when clause
+ */
+stree_when_t *stree_when_new(void)
+{
+	stree_when_t *when_c;
+
+	when_c = calloc(1, sizeof(stree_when_t));
+	if (when_c == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return when_c;
 }
 
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/stree.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -55,4 +55,5 @@
 stree_vdecl_t *stree_vdecl_new(void);
 stree_if_t *stree_if_new(void);
+stree_switch_t *stree_switch_new(void);
 stree_while_t *stree_while_new(void);
 stree_for_t *stree_for_new(void);
@@ -65,4 +66,5 @@
 stree_except_t *stree_except_new(void);
 stree_if_clause_t *stree_if_clause_new(void);
+stree_when_t *stree_when_new(void);
 stree_block_t *stree_block_new(void);
 
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/stree_t.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -364,5 +364,5 @@
 } texpr_class_t;
 
-/** Arithmetic expression */
+/** Type expression */
 typedef struct stree_texpr {
 	texpr_class_t tc;
@@ -394,4 +394,7 @@
 	stree_ident_t *name;
 	stree_texpr_t *type;
+
+	/** Type of this variable or @c NULL if not typed yet */
+	struct tdata_item *titem;
 } stree_vdecl_t;
 
@@ -401,4 +404,7 @@
 	stree_texpr_t *etype;
 	stree_block_t *block;
+
+	/** Evaluated etype or @c NULL if not typed yet */
+	struct tdata_item *titem;
 } stree_except_t;
 
@@ -418,4 +424,23 @@
 } stree_if_t;
 
+/** @c when clause */
+typedef struct {
+	/** List of expressions -- cases -- for this clause */
+	list_t exprs; /* of stree_expr_t */
+	stree_block_t *block;
+} stree_when_t;
+
+/** Switch statement */
+typedef struct {
+	/** Switch expression */
+	stree_expr_t *expr;
+
+	/** When clauses */
+	list_t when_clauses; /* of stree_when_t */
+
+	/** Else block */
+	stree_block_t *else_block;
+} stree_switch_t;
+
 /** While statement */
 typedef struct {
@@ -448,5 +473,5 @@
 } stree_exps_t;
 
-/** With-try-except-finally statement (WEF) */
+/** With-try-except-finally (WEF) statement */
 typedef struct {
 	stree_block_t *with_block;
@@ -459,4 +484,5 @@
 	st_vdecl,
 	st_if,
+	st_switch,
 	st_while,
 	st_for,
@@ -475,4 +501,5 @@
 		stree_vdecl_t *vdecl_s;
 		stree_if_t *if_s;
+		stree_switch_t *switch_s;
 		stree_while_t *while_s;
 		stree_for_t *for_s;
@@ -510,5 +537,5 @@
 /** Function signature.
  *
- * Foormal parameters and return type. This is common to function and delegate
+ * Formal parameters and return type. This is common to function and delegate
  * delcarations.
  */
@@ -788,11 +815,8 @@
 	} u;
 
-	/** Containing CSI (for all symbols) */
+	/** Containing CSI */
 	stree_csi_t *outer_csi;
 
-	/** Containing block (for block-level symbols) */
-	stree_block_t *outer_block;
-
-	/** Symbol attributes. */
+	/** Symbol attributes */
 	list_t attr; /* of stree_symbol_attr_t */
 } stree_symbol_t;
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/stype.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -76,4 +76,5 @@
 static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s);
 static void stype_if(stype_t *stype, stree_if_t *if_s);
+static void stype_switch(stype_t *stype, stree_switch_t *switch_s);
 static void stype_while(stype_t *stype, stree_while_t *while_s);
 static void stype_for(stype_t *stype, stree_for_t *for_s);
@@ -889,4 +890,5 @@
 	case st_vdecl: stype_vdecl(stype, stat->u.vdecl_s); break;
 	case st_if: stype_if(stype, stat->u.if_s); break;
+	case st_switch: stype_switch(stype, stat->u.switch_s); break;
 	case st_while: stype_while(stype, stat->u.while_s); break;
 	case st_for: stype_for(stype, stat->u.for_s); break;
@@ -931,4 +933,7 @@
 	}
 
+	/* Annotate with variable type */
+	vdecl_s->titem = titem;
+
 	intmap_set(&block_vr->vdecls, vdecl_s->name->sid, vdecl_s);
 }
@@ -973,4 +978,71 @@
 	if (if_s->else_block != NULL)
 		stype_block(stype, if_s->else_block);
+}
+
+/** Type @c switch statement.
+ *
+ * @param stype		Static typing object
+ * @param switch_s	@c switch statement
+ */
+static void stype_switch(stype_t *stype, stree_switch_t *switch_s)
+{
+	stree_expr_t *expr, *cexpr;
+	list_node_t *whenc_node;
+	stree_when_t *whenc;
+	list_node_t *expr_node;
+	tdata_item_t *titem1, *titem2;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Type 'switch' statement.\n");
+#endif
+	stype_expr(stype, switch_s->expr);
+
+	titem1 = switch_s->expr->titem;
+	if (titem1 == NULL) {
+		cspan_print(switch_s->expr->cspan);
+		printf(" Error: Switch expression has no value.\n");
+		stype_note_error(stype);
+		return;
+	}
+
+	/* Walk through all when clauses. */
+	whenc_node = list_first(&switch_s->when_clauses);
+
+	while (whenc_node != NULL) {
+		/* Get when clause */
+		whenc = list_node_data(whenc_node, stree_when_t *);
+
+		/* Walk through all expressions of the when clause */
+		expr_node = list_first(&whenc->exprs);
+		while (expr_node != NULL) {
+			expr = list_node_data(expr_node, stree_expr_t *);
+
+			stype_expr(stype, expr);
+			titem2 = expr->titem;
+			if (titem2 == NULL) {
+				cspan_print(expr->cspan);
+				printf(" Error: When expression has no value.\n");
+				stype_note_error(stype);
+				return;
+			}
+
+			/* Convert expression to same type as switch expr. */
+			cexpr = stype_convert(stype, expr, titem1);
+
+			/* Patch code with augmented expression. */
+			list_node_setdata(expr_node, cexpr);
+
+			expr_node = list_next(&whenc->exprs, expr_node);
+		}
+
+		/* Type the @c when block */
+		stype_block(stype, whenc->block);
+
+		whenc_node = list_next(&switch_s->when_clauses, whenc_node);
+	}
+
+	/* Type the @c else block */
+	if (switch_s->else_block != NULL)
+		stype_block(stype, switch_s->else_block);
 }
 
@@ -1168,4 +1240,6 @@
 	while (ec_n != NULL) {
 		ec = list_node_data(ec_n, stree_except_t *);
+		run_texpr(stype->program, stype->current_csi, ec->etype,
+		    &ec->titem);
 		stype_block(stype, ec->block);
 
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/app/sbi/src/stype_expr.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -894,4 +894,11 @@
 
 	titem = unop->arg->titem;
+	if (titem == NULL) {
+		cspan_print(unop->arg->cspan);
+		printf(" Error: Argument of unary operation has no value.\n");
+		stype_note_error(stype);
+		*rtitem = stype_recovery_titem(stype);
+		return;
+	}
 
 	if (titem->tic == tic_ignore) {
Index: uspace/dist/src/sysel/demos/arith.sy
===================================================================
--- uspace/dist/src/sysel/demos/arith.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/arith.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -30,57 +30,57 @@
 	fun Main(), static is
 		-- Test addition, multiplication and precedence.
-		Builtin.Write("2*2 + 2*2 = ");
-		Builtin.Write(2*2 + 2*2);
-		Builtin.WriteLine(" (expected: 8)");
+		Console.Write("2*2 + 2*2 = ");
+		Console.Write(2*2 + 2*2);
+		Console.WriteLine(" (expected: 8)");
 
 		-- Test subtraction, multiplication and precedence.
-		Builtin.Write("1111 - 1 - 10 - 10*10 - 10*10*10 = ");
-		Builtin.Write(1111 - 1 - 10 - 10*10 - 10*10*10);
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("1111 - 1 - 10 - 10*10 - 10*10*10 = ");
+		Console.Write(1111 - 1 - 10 - 10*10 - 10*10*10);
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test parenthesized sub-expressions.
-		Builtin.Write("10 * (1 - 1) = ");
-		Builtin.Write(10 * (1 - 1));
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("10 * (1 - 1) = ");
+		Console.Write(10 * (1 - 1));
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test unary plus and minus.
-		Builtin.Write("(+1) - (-1) - (+(+1)) + (+(-1)) = ");
-		Builtin.Write((+1) - (-1) - (+(+1)) + (+(-1)));
-		Builtin.WriteLine(" (expected: 0)");
+		Console.Write("(+1) - (-1) - (+(+1)) + (+(-1)) = ");
+		Console.Write((+1) - (-1) - (+(+1)) + (+(-1)));
+		Console.WriteLine(" (expected: 0)");
 
 		-- Test signed multiplication.
-		Builtin.Write("+1 * +1 = ");
-		Builtin.Write(+1 * +1);
-		Builtin.WriteLine(" (expected: 1)");
+		Console.Write("+1 * +1 = ");
+		Console.Write(+1 * +1);
+		Console.WriteLine(" (expected: 1)");
 
-		Builtin.Write("-1 * -1 = ");
-		Builtin.Write(-1 * -1);
-		Builtin.WriteLine(" (expected: 1)");
+		Console.Write("-1 * -1 = ");
+		Console.Write(-1 * -1);
+		Console.WriteLine(" (expected: 1)");
 
-		Builtin.Write("+1 * -1 = ");
-		Builtin.Write(+1 * -1);
-		Builtin.WriteLine(" (expected: -1)");
+		Console.Write("+1 * -1 = ");
+		Console.Write(+1 * -1);
+		Console.WriteLine(" (expected: -1)");
 
-		Builtin.Write("-1 * +1 = ");
-		Builtin.Write(-1 * +1);
-		Builtin.WriteLine(" (expected: -1)");
+		Console.Write("-1 * +1 = ");
+		Console.Write(-1 * +1);
+		Console.WriteLine(" (expected: -1)");
 
 		-- Test multiplication with large result.
-		Builtin.Write("1000000 * 1000000 * 1000000 * 1000000 = ");
-		Builtin.Write(1000000 * 1000000 * 1000000 * 1000000);
-		Builtin.WriteLine(" (expected: 1000000000000000000000000)");
+		Console.Write("1000000 * 1000000 * 1000000 * 1000000 = ");
+		Console.Write(1000000 * 1000000 * 1000000 * 1000000);
+		Console.WriteLine(" (expected: 1000000000000000000000000)");
 
 		-- Test large literals.
-		Builtin.Write("1000000000000000000000000 = ");
-		Builtin.Write(1000000000000000000000000);
-		Builtin.WriteLine(" (expected: 1000000000000000000000000)");
+		Console.Write("1000000000000000000000000 = ");
+		Console.Write(1000000000000000000000000);
+		Console.WriteLine(" (expected: 1000000000000000000000000)");
 
 		-- Test large factorials.
 		var n : int;
 
-		Builtin.WriteLine("Factorials:");
+		Console.WriteLine("Factorials:");
 		n = 1;
 		while n <= 40 do
-			Builtin.WriteLine(Factorial(n));
+			Console.WriteLine(Factorial(n));
 			n = n + 1;
 		end
Index: uspace/dist/src/sysel/demos/array.sy
===================================================================
--- uspace/dist/src/sysel/demos/array.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/array.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -40,5 +40,5 @@
 		i = 0;
 		while i < 3 do
-			Builtin.WriteLine(a[i, 0]);
+			Console.WriteLine(a[i, 0]);
 			i = i + 1;
 		end
Index: uspace/dist/src/sysel/demos/autobox.sy
===================================================================
--- uspace/dist/src/sysel/demos/autobox.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/autobox.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -39,11 +39,11 @@
 		--
 		b = true;
-		Builtin.WriteLine(b.Value);
+		Console.WriteLine(b.Value);
 		c = 'a';
-		Builtin.WriteLine(c.Value);
+		Console.WriteLine(c.Value);
 		i = 1;
-		Builtin.WriteLine(i.Value);
+		Console.WriteLine(i.Value);
 		s = "Hello";
-		Builtin.WriteLine(s.Value);
+		Console.WriteLine(s.Value);
 
 		-- Anything can be converted to Object.
Index: uspace/dist/src/sysel/demos/count.sy
===================================================================
--- uspace/dist/src/sysel/demos/count.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/count.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -33,5 +33,5 @@
 		i = a;
 		while i < b do
-			Builtin.WriteLine(i);
+			Console.WriteLine(i);
 			i = i + 1;
 		end
Index: uspace/dist/src/sysel/demos/ctor.sy
===================================================================
--- uspace/dist/src/sysel/demos/ctor.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/ctor.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -32,6 +32,6 @@
 
 		a = new A(1);
-		Builtin.Write("a.v = ");
-		Builtin.WriteLine(a.v);
+		Console.Write("a.v = ");
+		Console.WriteLine(a.v);
 	end
 end
@@ -41,5 +41,5 @@
 
 	new(i : int) is
-		Builtin.WriteLine("A.new()");
+		Console.WriteLine("A.new()");
 		v = i;
 	end
Index: uspace/dist/src/sysel/demos/deleg.sy
===================================================================
--- uspace/dist/src/sysel/demos/deleg.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/deleg.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -55,6 +55,6 @@
 	-- Function having delegate as the first parameger
 	fun Operate(op : BinaryOp; opName : string) is
-		Builtin.Write(opName + "(1, 2): ");
-		Builtin.WriteLine(op(1, 2));
+		Console.Write(opName + "(1, 2): ");
+		Console.WriteLine(op(1, 2));
 	end
 
Index: uspace/dist/src/sysel/demos/enum.sy
===================================================================
--- uspace/dist/src/sysel/demos/enum.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/enum.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -31,40 +31,40 @@
 		var color : ChessColor;
 
-		Builtin.WriteLine("Set color to ChessColor.Black.");
+		Console.WriteLine("Set color to ChessColor.Black.");
 		color = ChessColor.Black;
 
-		Builtin.Write("Test color == ChessColor.Black.. ");
+		Console.Write("Test color == ChessColor.Black.. ");
 		if color == ChessColor.Black then
-			Builtin.WriteLine("True - OK");
+			Console.WriteLine("True - OK");
 		else
-			Builtin.WriteLine("False - Fail!");
+			Console.WriteLine("False - Fail!");
 			raise new Error.Base();
 		end
 
-		Builtin.Write("Test color != ChessColor.Black.. ");
+		Console.Write("Test color != ChessColor.Black.. ");
 		if color != ChessColor.Black then
-			Builtin.WriteLine("True - Fail!");
+			Console.WriteLine("True - Fail!");
 			raise new Error.Base();
 		else
-			Builtin.WriteLine("False - OK");
+			Console.WriteLine("False - OK");
 		end
 
-		Builtin.Write("Test color == ChessColor.White.. ");
+		Console.Write("Test color == ChessColor.White.. ");
 		if color == ChessColor.White then
-			Builtin.WriteLine("True - Fail!");
+			Console.WriteLine("True - Fail!");
 			raise new Error.Base();
 		else
-			Builtin.WriteLine("False - OK");
+			Console.WriteLine("False - OK");
 		end
 
-		Builtin.Write("Test color != ChessColor.White.. ");
+		Console.Write("Test color != ChessColor.White.. ");
 		if color != ChessColor.White then
-			Builtin.WriteLine("True - OK");
+			Console.WriteLine("True - OK");
 		else
-			Builtin.WriteLine("False - Fail!");
+			Console.WriteLine("False - Fail!");
 			raise new Error.Base();
 		end
 
-		Builtin.WriteLine("Success");
+		Console.WriteLine("Success");
 
 		-- Test enum declared in non-CSI scope
Index: uspace/dist/src/sysel/demos/except.sy
===================================================================
--- uspace/dist/src/sysel/demos/except.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/except.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -29,5 +29,5 @@
 class ExceptionDemo is
 	fun foo(), static is
-	        Builtin.WriteLine("Entered foo().");
+	        Console.WriteLine("Entered foo().");
 		raise new BaseException();
 	end
@@ -38,9 +38,9 @@
 			foo();
 		except e : DerivedException do
-			Builtin.WriteLine("Caught derived exception.");
+			Console.WriteLine("Caught derived exception.");
 		except e : BaseException do
-			Builtin.WriteLine("Caught base exception.");
+			Console.WriteLine("Caught base exception.");
 		finally do
-			Builtin.WriteLine("Finally.");
+			Console.WriteLine("Finally.");
 		end
 	end
Index: uspace/dist/src/sysel/demos/gen.sy
===================================================================
--- uspace/dist/src/sysel/demos/gen.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/gen.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -31,5 +31,5 @@
 class GenericsDemo is
 	fun Main(), static is
-		Builtin.WriteLine("Let's try some generics.");
+		Console.WriteLine("Let's try some generics.");
 
 		var f : B/int/string;
Index: uspace/dist/src/sysel/demos/hello.sy
===================================================================
--- uspace/dist/src/sysel/demos/hello.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/hello.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -29,5 +29,5 @@
 class HelloWorld is
 	fun Main(), static is
-		Builtin.WriteLine("Hello world!");
+		Console.WriteLine("Hello world!");
 	end
 end
Index: uspace/dist/src/sysel/demos/htxtfile.sy
===================================================================
--- uspace/dist/src/sysel/demos/htxtfile.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/htxtfile.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -45,5 +45,5 @@
 		while not in_file.EOF do
 			line = in_file.ReadLine();
-			Builtin.WriteLine(name + ": " + line);
+			Console.WriteLine(name + ": " + line);
 			out_file.WriteLine(name + ": " + line);
 		end
Index: uspace/dist/src/sysel/demos/iface.sy
===================================================================
--- uspace/dist/src/sysel/demos/iface.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/iface.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -43,5 +43,5 @@
 		f = g as Foo;
 
-		Builtin.WriteLine(g.a());
+		Console.WriteLine(g.a());
 	end
 end
Index: uspace/dist/src/sysel/demos/inherit.sy
===================================================================
--- uspace/dist/src/sysel/demos/inherit.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/inherit.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -29,5 +29,5 @@
 class A is
 	fun Foo() is
-		Builtin.WriteLine("A.Foo()");
+		Console.WriteLine("A.Foo()");
 	end
 end
@@ -35,5 +35,5 @@
 class B : A is
 	fun Foo() is
-		Builtin.WriteLine("B.Foo()");
+		Console.WriteLine("B.Foo()");
 	end
 end
Index: uspace/dist/src/sysel/demos/list.sy
===================================================================
--- uspace/dist/src/sysel/demos/list.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/list.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -43,5 +43,5 @@
 		e = list.GetEnumerator();
 		while e.MoveNext() do
-			Builtin.WriteLine(e.Data);
+			Console.WriteLine(e.Data);
 		end
 	end
Index: uspace/dist/src/sysel/demos/map.sy
===================================================================
--- uspace/dist/src/sysel/demos/map.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/map.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -43,7 +43,7 @@
 		e = map.GetEnumerator();
 		while e.MoveNext() do
-			Builtin.Write(e.Data);
-			Builtin.Write(" -> ");
-			Builtin.WriteLine(map[e.Data]);
+			Console.Write(e.Data);
+			Console.Write(" -> ");
+			Console.WriteLine(map[e.Data]);
 		end
 	end
Index: uspace/dist/src/sysel/demos/property.sy
===================================================================
--- uspace/dist/src/sysel/demos/property.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/property.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -33,14 +33,25 @@
 	prop X : int is
 		get is
-			Builtin.Write("Getting value of X which is ");
-			Builtin.WriteLine(x);
+			Console.Write("Getting value of X which is ");
+			Console.WriteLine(x);
 			return x;
 		end
 
 		set value is
-			Builtin.Write("Setting value of X to ");
-			Builtin.WriteLine(value);
+			Console.Write("Setting value of X to ");
+			Console.WriteLine(value);
 			x = value;
 		end
+	end
+
+	-- Test accessing property via an unqualified name
+	fun TestUnqualPropAcc() is
+		var i : int;
+
+		X = 1;
+		i = X;
+
+		Console.Write("TestUnqualPropAcc(): Got ");
+		Console.WriteLine(i);
 	end
 
@@ -51,8 +62,8 @@
 	prop self[index : int] : int is
 		get is
-			Builtin.Write("Getting property with index ");
-			Builtin.Write(index);
-			Builtin.Write(" which is ");
-			Builtin.WriteLine(iprops[index]);
+			Console.Write("Getting property with index ");
+			Console.Write(index);
+			Console.Write(" which is ");
+			Console.WriteLine(iprops[index]);
 
 			return iprops[index];
@@ -60,8 +71,8 @@
 
 		set value is
-			Builtin.Write("Setting property with index ");
-			Builtin.Write(index);
-			Builtin.Write(" to ");
-			Builtin.WriteLine(value);
+			Console.Write("Setting property with index ");
+			Console.Write(index);
+			Console.Write(" to ");
+			Console.WriteLine(value);
 
 			iprops[index] = value;
@@ -82,9 +93,9 @@
 	prop B : Bar is
 		get is
-			Builtin.WriteLine("Getting B");
+			Console.WriteLine("Getting B");
 			return bprop;
 		end
 		set value is
-			Builtin.WriteLine("Setting B");
+			Console.WriteLine("Setting B");
 			bprop = value;
 		end
@@ -110,6 +121,8 @@
 		i = a.X;
 
-		Builtin.Write("Main(): Got ");
-		Builtin.WriteLine(i);
+		Console.Write("Main(): Got ");
+		Console.WriteLine(i);
+
+		a.TestUnqualPropAcc();
 
 		a.iprops = new int[5];
@@ -121,6 +134,6 @@
 		i = a[1];
 
-		Builtin.Write("Main(): Got ");
-		Builtin.WriteLine(i);
+		Console.Write("Main(): Got ");
+		Console.WriteLine(i);
 
 		-- Property field access
@@ -132,7 +145,7 @@
 		a.bprop = b;
 
-		Builtin.WriteLine(a.bprop.i);
+		Console.WriteLine(a.bprop.i);
 		a.bprop.i = 2;
-		Builtin.WriteLine(a.bprop.i);
+		Console.WriteLine(a.bprop.i);
 	end
 end
Index: uspace/dist/src/sysel/demos/string.sy
===================================================================
--- uspace/dist/src/sysel/demos/string.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/string.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -30,5 +30,5 @@
 	fun Main(), static is
 		-- Concatenate some strings.
-		Builtin.WriteLine("One-" + "two-" + "three!");
+		Console.WriteLine("One-" + "two-" + "three!");
 
 		-- Extract characters from a string.
@@ -36,9 +36,9 @@
 		i = 0;
 		while i < 5 do
-			Builtin.WriteLine("ABCDE"[i]);
+			Console.WriteLine("ABCDE"[i]);
 			i = i + 1;
 		end
 
-		Builtin.WriteLine("Abracadabra".Slice(2, 4));
+		Console.WriteLine("Abracadabra".Slice(2, 4));
 	end
 end
Index: uspace/dist/src/sysel/demos/svar.sy
===================================================================
--- uspace/dist/src/sysel/demos/svar.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/svar.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -31,13 +31,13 @@
 		-- Test static member variable
 		A.B.a = 1;
-		Builtin.WriteLine(A.B.a);
+		Console.WriteLine(A.B.a);
 		A.B.a = 2;
-		Builtin.WriteLine(A.B.a);
+		Console.WriteLine(A.B.a);
 
 		-- Test static property
 		A.B.P = 1;
-		Builtin.WriteLine(A.B.P);
+		Console.WriteLine(A.B.P);
 		A.B.P = 2;
-		Builtin.WriteLine(A.B.P);
+		Console.WriteLine(A.B.P);
 	end
 end
Index: uspace/dist/src/sysel/demos/switch.sy
===================================================================
--- uspace/dist/src/sysel/demos/switch.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/dist/src/sysel/demos/switch.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -0,0 +1,199 @@
+--
+-- Copyright (c) 2011 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:
+--
+-- o Redistributions of source code must retain the above copyright
+--   notice, this list of conditions and the following disclaimer.
+-- o 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.
+-- o 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.
+--
+
+--- Switch statement demo.
+--
+-- This demonstrates the switch statement. The switch statement looks like:
+--
+-- switch <s_expr> is
+-- when <e1> [, <e2> ...] do
+--	<statements1>
+-- when <f1> [, <f2> ...] do
+--	<statements2>
+-- [...]
+-- [else do
+--	<statements3>]
+-- end
+--
+-- It is mostly equivalent to the pseudocode:
+--
+-- var v : <type of s_expr>;
+-- if v == <e1> [or v == <e2> ...] then
+--	<statements1>
+-- elif v == <f1> [ or v == <f2> ...] then
+--	<statements2>
+-- [...]
+-- [else
+--	<statements3>]
+-- end
+--
+-- This means there is no artificial limitation as to what you can switch
+-- on. The expressions don't have to be constant and they can be of any type
+-- as long as the switch expression (<s_expr>) can be compared with each
+-- of the when expressions (<e1>, <e2>, <f1>, <f2>, ...).
+--
+-- Note however, the 'or' here denotes short-circuit evaluation. (Currently
+-- the 'or' operation does not use short-circuit evaluation, but that's
+-- more of a bug than a feature.
+--
+class SwitchDemo is
+	class A is
+	end
+
+	var a1 : A, static;
+	var a2 : A, static;
+	var a3 : A, static;
+	var a4 : A, static;
+
+	enum MyEnum is
+		red;
+		green;
+		blue;
+		black;
+		cyan;
+	end
+
+	-- Switch on boolean value
+	fun SwitchBool(v : bool) : string, static is
+		switch v is
+		when false do
+			return "false";
+		when true do
+			return "true";
+		end
+	end
+
+	-- Switch on char value
+	fun SwitchChar(v : char) : string, static is
+		switch v is
+		when 'a', 'b' do
+			return "a/b";
+		when 'c', 'd' do
+			return "c/d";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on integer value
+	fun SwitchInt(v : int) : string, static is
+		switch v is
+		when 0, 1 do
+			return "0/1";
+		when 2, 3 do
+			return "2/3";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on string value
+	fun SwitchString(v : string) : string, static is
+		switch v is
+		when "foo", "bar"  do
+			return "foo/bar";
+		when "hello", "world" do
+			return "hello/world";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on object reference
+	fun SwitchObj(v : A) : string, static is
+		switch v is
+		when a1, a2 do
+			return "a1/a2";
+		when a3, a4 do
+			return "a3/a4";
+		else do
+			return "<other>";
+		end
+	end
+
+	-- Switch on object reference
+	fun SwitchEnum(v : MyEnum) : string, static is
+		switch v is
+		when MyEnum.red, MyEnum.green do
+			return "red/green";
+		when MyEnum.blue, MyEnum.black do
+			return "blue/black";
+		else do
+			return "<other>";
+		end
+	end
+
+	fun Test(res : string; test_expr : string; expected : string), static is
+		Console.WriteLine(test_expr + " = '" + res + "' (expected '" +
+		    expected + "')");
+		if res != expected then
+			Console.WriteLine("Error: Got unexpected result.");
+			raise new Error.Base();
+		end
+	end
+
+	fun Main(), static is
+		a1 = new A();
+		a2 = new A();
+		a3 = new A();
+		a4 = new A();
+
+		Test(SwitchBool(false), "SwitchBool(false)", "false");
+		Test(SwitchBool(true), "SwitchBool(true)", "true");
+
+		Test(SwitchChar('a'), "SwitchChar('a')", "a/b");
+		Test(SwitchChar('b'), "SwitchChar('b')", "a/b");
+		Test(SwitchChar('c'), "SwitchChar('c')", "c/d");
+		Test(SwitchChar('d'), "SwitchChar('d')", "c/d");
+		Test(SwitchChar('e'), "SwitchChar('e')", "<other>");
+
+		Test(SwitchInt(0), "SwitchInt(0)", "0/1");
+		Test(SwitchInt(1), "SwitchInt(1)", "0/1");
+		Test(SwitchInt(2), "SwitchInt(2)", "2/3");
+		Test(SwitchInt(3), "SwitchInt(3)", "2/3");
+		Test(SwitchInt(4), "SwitchInt(4)", "<other>");
+
+		Test(SwitchString("foo"), "SwitchString('foo')", "foo/bar");
+		Test(SwitchString("bar"), "SwitchString('bar')", "foo/bar");
+		Test(SwitchString("hello"), "SwitchString('hello')", "hello/world");
+		Test(SwitchString("world"), "SwitchString('world')", "hello/world");
+		Test(SwitchString("boom"), "SwitchString('boom')", "<other>");
+
+		Test(SwitchObj(a1), "SwitchObj(a1)", "a1/a2");
+		Test(SwitchObj(a2), "SwitchObj(a2)", "a1/a2");
+		Test(SwitchObj(a3), "SwitchObj(a3)", "a3/a4");
+		Test(SwitchObj(a4), "SwitchObj(a4)", "a3/a4");
+		Test(SwitchObj(nil), "SwitchObj(nil)", "<other>");
+
+		Test(SwitchEnum(MyEnum.red), "SwitchEnum(MyEnum.red)", "red/green");
+		Test(SwitchEnum(MyEnum.green), "SwitchEnum(MyEnum.green)", "red/green");
+		Test(SwitchEnum(MyEnum.blue), "SwitchEnum(MyEnum.blue)", "blue/black");
+		Test(SwitchEnum(MyEnum.black), "SwitchEnum(MyEnum.black)", "blue/black");
+		Test(SwitchEnum(MyEnum.cyan), "SwitchEnum(MyEnum.cyan)", "<other>");
+	end
+end
Index: uspace/dist/src/sysel/demos/varargs.sy
===================================================================
--- uspace/dist/src/sysel/demos/varargs.sy	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/dist/src/sysel/demos/varargs.sy	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -44,5 +44,5 @@
 			-- implemented...
 			do
-				Builtin.WriteLine(args[i]);
+				Console.WriteLine(args[i]);
 			except e : Error.OutOfBounds do
 				error = true;
Index: uspace/drv/usbhid/hiddev.c
===================================================================
--- uspace/drv/usbhid/hiddev.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhid/hiddev.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -158,4 +158,6 @@
 	}
 	
+	hid_dev->report_desc_size = length;
+	
 	usb_log_debug("Done.\n");
 	
@@ -262,8 +264,18 @@
 	
 	if (rc != EOK) {
-		usb_log_warning("Problem with parsing Report descriptor: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
+		usb_log_warning("Problem with getting Report descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	rc = usb_hid_parse_report_descriptor(hid_dev->parser, 
+	    hid_dev->report_desc, hid_dev->report_desc_size);
+	if (rc != EOK) {
+		usb_log_warning("Problem parsing Report descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_hid_descriptor_print(hid_dev->parser);
 	
 	return EOK;
@@ -289,4 +301,12 @@
 	
 	memset(dev, 0, sizeof(usbhid_dev_t));
+	
+	dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
+	    usb_hid_report_parser_t)));
+	if (dev->parser == NULL) {
+		usb_log_fatal("No memory!\n");
+		free(dev);
+		return NULL;
+	}
 	
 	dev->initialized = 0;
@@ -399,4 +419,13 @@
 
 	/*
+	 * Initialize the report parser.
+	 */
+	rc = usb_hid_parser_init(hid_dev->parser);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize report parser.\n");
+		return rc;
+	}
+
+	/*
 	 * Get descriptors, parse descriptors and save endpoints.
 	 */
Index: uspace/drv/usbhid/hiddev.h
===================================================================
--- uspace/drv/usbhid/hiddev.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhid/hiddev.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -75,4 +75,7 @@
 	/** Report descriptor. */
 	uint8_t *report_desc;
+
+	size_t report_desc_size;
+
 	/** HID Report parser. */
 	usb_hid_report_parser_t *parser;
Index: uspace/drv/usbhid/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbddev.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhid/kbddev.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -51,4 +51,5 @@
 #include <usb/classes/hidparser.h>
 #include <usb/classes/classes.h>
+#include <usb/classes/hidut.h>
 
 #include "kbddev.h"
@@ -122,4 +123,17 @@
 	KC_RALT,          /* USB_HID_MOD_RALT */
 	0,                /* USB_HID_MOD_RGUI */
+};
+
+typedef enum usbhid_lock_code {
+	USBHID_LOCK_NUM = 0x53,
+	USBHID_LOCK_CAPS = 0x39,
+	USBHID_LOCK_SCROLL = 0x47,
+	USBHID_LOCK_COUNT = 3
+} usbhid_lock_code;
+
+static const usbhid_lock_code usbhid_lock_codes[USBHID_LOCK_COUNT] = {
+	USBHID_LOCK_NUM,
+	USBHID_LOCK_CAPS,
+	USBHID_LOCK_SCROLL
 };
 
@@ -346,36 +360,45 @@
  * @sa usbhid_kbd_push_ev()
  */
-static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev,
-    uint8_t modifiers)
-{
-	/*
-	 * TODO: why the USB keyboard has NUM_, SCROLL_ and CAPS_LOCK
-	 *       both as modifiers and as keys with their own scancodes???
-	 *
-	 * modifiers should be sent as normal keys to usbhid_parse_scancode()!!
-	 * so maybe it would be better if I received it from report parser in 
-	 * that way
-	 */
-	
-	int i;
-	for (i = 0; i < USB_HID_MOD_COUNT; ++i) {
-		if ((modifiers & usb_hid_modifiers_consts[i]) &&
-		    !(kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
-			// modifier pressed
-			if (usbhid_modifiers_keycodes[i] != 0) {
-				usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, 
-				    usbhid_modifiers_keycodes[i]);
-			}
-		} else if (!(modifiers & usb_hid_modifiers_consts[i]) &&
-		    (kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
-			// modifier released
-			if (usbhid_modifiers_keycodes[i] != 0) {
-				usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, 
-				    usbhid_modifiers_keycodes[i]);
-			}
-		}	// no change
-	}
-	
-	kbd_dev->modifiers = modifiers;
+//static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev, 
+//    const uint8_t *key_codes, size_t count)
+//{
+//	/*
+//	 * TODO: why the USB keyboard has NUM_, SCROLL_ and CAPS_LOCK
+//	 *       both as modifiers and as keyUSB_HID_LOCK_COUNTs with their own scancodes???
+//	 *
+//	 * modifiers should be sent as normal keys to usbhid_parse_scancode()!!
+//	 * so maybe it would be better if I received it from report parser in 
+//	 * that way
+//	 */
+	
+//	int i;
+//	for (i = 0; i < count; ++i) {
+//		if ((modifiers & usb_hid_modifiers_consts[i]) &&
+//		    !(kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
+//			// modifier pressed
+//			if (usbhid_modifiers_keycodes[i] != 0) {
+//				usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, 
+//				    usbhid_modifiers_keycodes[i]);
+//			}
+//		} else if (!(modifiers & usb_hid_modifiers_consts[i]) &&
+//		    (kbd_dev->modifiers & usb_hid_modifiers_consts[i])) {
+//			// modifier released
+//			if (usbhid_modifiers_keycodes[i] != 0) {
+//				usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, 
+//				    usbhid_modifiers_keycodes[i]);
+//			}
+//		}	// no change
+//	}
+	
+//	kbd_dev->modifiers = modifiers;
+//}
+
+/*----------------------------------------------------------------------------*/
+
+static inline int usbhid_kbd_is_lock(unsigned int key_code) 
+{
+	return (key_code == KC_NUM_LOCK
+	    || key_code == KC_SCROLL_LOCK
+	    || key_code == KC_CAPS_LOCK);
 }
 
@@ -404,4 +427,7 @@
 	/*
 	 * First of all, check if the kbd have reported phantom state.
+	 *
+	 * TODO: this must be changed as we don't know which keys are modifiers
+	 *       and which are regular keys.
 	 */
 	i = 0;
@@ -434,5 +460,7 @@
 			// not found, i.e. the key was released
 			key = usbhid_parse_scancode(kbd_dev->keys[j]);
-			usbhid_kbd_repeat_stop(kbd_dev, key);
+			if (!usbhid_kbd_is_lock(key)) {
+				usbhid_kbd_repeat_stop(kbd_dev, key);
+			}
 			usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
 			usb_log_debug2("Key released: %d\n", key);
@@ -458,5 +486,7 @@
 			    key_codes[i]);
 			usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key);
-			usbhid_kbd_repeat_start(kbd_dev, key);
+			if (!usbhid_kbd_is_lock(key)) {
+				usbhid_kbd_repeat_start(kbd_dev, key);
+			}
 		} else {
 			// found, nothing happens
@@ -502,5 +532,5 @@
 
 	usb_log_debug("Got keys from parser: %s\n", 
-	    usb_debug_str_buffer(key_codes, kbd_dev->key_count, 0));
+	    usb_debug_str_buffer(key_codes, count, 0));
 	
 	if (count != kbd_dev->key_count) {
@@ -510,5 +540,5 @@
 	}
 	
-	usbhid_kbd_check_modifier_changes(kbd_dev, modifiers);
+	///usbhid_kbd_check_modifier_changes(kbd_dev, key_codes, count);
 	usbhid_kbd_check_key_changes(kbd_dev, key_codes, count);
 }
@@ -535,4 +565,7 @@
                                     uint8_t *buffer, size_t actual_size)
 {
+	assert(kbd_dev->initialized);
+	assert(kbd_dev->hid_dev->parser != NULL);
+	
 	usb_hid_report_in_callbacks_t *callbacks =
 	    (usb_hid_report_in_callbacks_t *)malloc(
@@ -541,9 +574,11 @@
 	callbacks->keyboard = usbhid_kbd_process_keycodes;
 
-	usb_log_debug("Calling usb_hid_boot_keyboard_input_report() with "
+	usb_log_debug("Calling usb_hid_parse_report() with "
 	    "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
 	
-	int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
-	    callbacks, kbd_dev);
+//	int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
+//	    callbacks, kbd_dev);
+	int rc = usb_hid_parse_report(kbd_dev->hid_dev->parser, buffer,
+	    actual_size, callbacks, kbd_dev);
 	
 	if (rc != EOK) {
@@ -614,5 +649,5 @@
 		free((*kbd_dev)->repeat_mtx);
 	}
-	
+
 	free(*kbd_dev);
 	*kbd_dev = NULL;
@@ -674,5 +709,13 @@
 	
 	// save the size of the report (boot protocol report by default)
-	kbd_dev->key_count = BOOTP_REPORT_SIZE;
+//	kbd_dev->key_count = BOOTP_REPORT_SIZE;
+	
+	usb_hid_report_path_t path;
+	path.usage_page = USB_HIDUT_PAGE_KEYBOARD;
+	kbd_dev->key_count = usb_hid_report_input_length(
+	    kbd_dev->hid_dev->parser, &path);
+	
+	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
+	
 	kbd_dev->keys = (uint8_t *)calloc(
 	    kbd_dev->key_count, sizeof(uint8_t));
@@ -709,5 +752,5 @@
 	assert(kbd_dev->hid_dev != NULL);
 	assert(kbd_dev->hid_dev->initialized);
-	usbhid_req_set_protocol(kbd_dev->hid_dev, USB_HID_PROTOCOL_BOOT);
+	//usbhid_req_set_protocol(kbd_dev->hid_dev, USB_HID_PROTOCOL_BOOT);
 	
 	usbhid_kbd_set_led(kbd_dev);
Index: uspace/drv/usbhid/kbddev.h
===================================================================
--- uspace/drv/usbhid/kbddev.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhid/kbddev.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -42,4 +42,5 @@
 
 #include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
 #include <ddf/driver.h>
 #include <usb/pipes.h>
Index: uspace/drv/usbhub/port_status.h
===================================================================
--- uspace/drv/usbhub/port_status.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhub/port_status.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -270,4 +270,21 @@
 }
 
+//low speed device attached
+static inline bool usb_port_high_speed(usb_port_status_t * status){
+	return usb_port_get_bit(status,10);
+}
+
+static inline void usb_port_set_high_speed(usb_port_status_t * status,bool high_speed){
+	usb_port_set_bit(status,10,high_speed);
+}
+
+static inline usb_speed_t usb_port_speed(usb_port_status_t * status){
+	if(usb_port_low_speed(status))
+		return USB_SPEED_LOW;
+	if(usb_port_high_speed(status))
+		return USB_SPEED_HIGH;
+	return USB_SPEED_FULL;
+}
+
 
 //connect change
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhub/usbhub.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -78,6 +78,6 @@
 		async_usleep(1000 * 1000 );/// \TODO proper number once
 	}
-	dprintf(USB_LOG_LEVEL_ERROR,
-				"something in ctrl loop went wrong, errno %d",errorCode);
+	usb_log_error("something in ctrl loop went wrong, errno %d",errorCode);
+
 	return 0;
 }
@@ -104,6 +104,5 @@
 			hub->device);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"could not initialize connection to hc, errno %d",opResult);
+		usb_log_error("could not initialize connection to hc, errno %d",opResult);
 		return opResult;
 	}
@@ -112,6 +111,6 @@
 			hub->device);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"could not initialize connection to device, errno %d",opResult);
+		usb_log_error("could not initialize connection to device, errno %d",
+				opResult);
 		return opResult;
 	}
@@ -120,6 +119,6 @@
             &hub->device_connection);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"could not initialize connection to device endpoint, errno %d",opResult);
+		usb_log_error("could not initialize connection to device endpoint, errno %d",
+				opResult);
 		return opResult;
 	}
@@ -127,5 +126,5 @@
 	opResult = usb_endpoint_pipe_probe_default_control(&hub->endpoints.control);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, "failed probing endpoint 0, %d", opResult);
+		usb_log_error("failed probing endpoint 0, %d", opResult);
 		return opResult;
 	}
@@ -151,11 +150,11 @@
 	    &std_descriptor);
 	if(opResult!=EOK){
-		dprintf(USB_LOG_LEVEL_ERROR, "could not get device descriptor, %d",opResult);
-		return opResult;
-	}
-	dprintf(USB_LOG_LEVEL_INFO, "hub has %d configurations",
+		usb_log_error("could not get device descriptor, %d",opResult);
+		return opResult;
+	}
+	usb_log_info("hub has %d configurations",
 			std_descriptor.configuration_count);
 	if(std_descriptor.configuration_count<1){
-		dprintf(USB_LOG_LEVEL_ERROR, "THERE ARE NO CONFIGURATIONS AVAILABLE");
+		usb_log_error("THERE ARE NO CONFIGURATIONS AVAILABLE");
 		//shouldn`t I return?
 	}
@@ -184,5 +183,5 @@
 		return opResult;
 	}
-	dprintf(USB_LOG_LEVEL_DEBUG, "\tused configuration %d",
+	usb_log_debug("\tused configuration %d",
 			config_descriptor->configuration_number);
 
@@ -200,11 +199,10 @@
 	    &hub->device_connection);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"Failed to initialize status change pipe: %s",
+		usb_log_error("Failed to initialize status change pipe: %s",
 		    str_error(opResult));
 		return opResult;
 	}
 	if (!endpoint_mapping[0].present) {
-		dprintf(USB_LOG_LEVEL_ERROR,"Not accepting device, " \
+		usb_log_error("Not accepting device, " \
 		    "cannot understand what is happenning");
 		return EREFUSED;
@@ -235,4 +233,5 @@
 	result->port_count = -1;
 	result->device = device;
+	result->is_default_address_used = false;
 
 	//result->usb_device = usb_new(usb_hcd_attached_device_info_t);
@@ -240,8 +239,8 @@
 
 	// get hub descriptor
-	dprintf(USB_LOG_LEVEL_DEBUG, "creating serialized descripton");
+	usb_log_debug("creating serialized descripton");
 	void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
 	usb_hub_descriptor_t * descriptor;
-	dprintf(USB_LOG_LEVEL_DEBUG, "starting control transaction");
+	usb_log_debug("starting control transaction");
 	usb_endpoint_pipe_start_session(&result->endpoints.control);
 	opResult = usb_request_set_configuration(&result->endpoints.control, 1);
@@ -256,18 +255,19 @@
 
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, "failed when receiving hub descriptor, badcode = %d",opResult);
+		usb_log_error("failed when receiving hub descriptor, badcode = %d",
+				opResult);
 		free(serialized_descriptor);
 		free(result);
 		return NULL;
 	}
-	dprintf(USB_LOG_LEVEL_DEBUG2, "deserializing descriptor");
+	usb_log_debug2("deserializing descriptor");
 	descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
 	if(descriptor==NULL){
-		dprintf(USB_LOG_LEVEL_WARNING, "could not deserialize descriptor ");
+		usb_log_warning("could not deserialize descriptor ");
 		free(result);
 		return NULL;
 	}
 
-	dprintf(USB_LOG_LEVEL_INFO, "setting port count to %d",descriptor->ports_count);
+	usb_log_info("setting port count to %d",descriptor->ports_count);
 	result->port_count = descriptor->ports_count;
 	result->attached_devs = (usb_hc_attached_device_t*)
@@ -278,5 +278,5 @@
 		result->attached_devs[i].address=0;
 	}
-	dprintf(USB_LOG_LEVEL_DEBUG2, "freeing data");
+	usb_log_debug2("freeing data");
 	free(serialized_descriptor);
 	free(descriptor->devices_removable);
@@ -285,5 +285,5 @@
 	//finish
 
-	dprintf(USB_LOG_LEVEL_INFO, "hub info created");
+	usb_log_info("hub info created");
 
 	return result;
@@ -296,5 +296,5 @@
  */
 int usb_add_hub_device(ddf_dev_t *dev) {
-	dprintf(USB_LOG_LEVEL_INFO, "add_hub_device(handle=%d)", (int) dev->handle);
+	usb_log_info("add_hub_device(handle=%d)", (int) dev->handle);
 
 	//dev->ops = &hub_device_ops;
@@ -313,5 +313,5 @@
 	opResult = usb_hub_process_configuration_descriptors(hub_info);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,"could not get configuration descriptors, %d",
+		usb_log_error("could not get configuration descriptors, %d",
 				opResult);
 		return opResult;
@@ -324,7 +324,7 @@
 		opResult = usb_endpoint_pipe_control_write(&hub_info->endpoints.control,
 				&request,sizeof(usb_device_request_setup_packet_t), NULL, 0);
-		dprintf(USB_LOG_LEVEL_INFO, "powering port %d",port);
+		usb_log_info("powering port %d",port);
 		if (opResult != EOK) {
-			dprintf(USB_LOG_LEVEL_WARNING, "something went wrong when setting hub`s %dth port", port);
+			usb_log_warning("something went wrong when setting hub`s %dth port", port);
 		}
 	}
@@ -337,7 +337,7 @@
 	usb_lst_append(&usb_hub_list, hub_info);
 	fibril_mutex_unlock(&usb_hub_list_lock);
-	dprintf(USB_LOG_LEVEL_DEBUG, "hub info added to list");
-
-	dprintf(USB_LOG_LEVEL_DEBUG, "adding to ddf");
+	usb_log_debug("hub info added to list");
+
+	usb_log_debug("adding to ddf");
 	ddf_fun_t *hub_fun = ddf_fun_create(dev, fun_exposed, "hub");
 	assert(hub_fun != NULL);
@@ -351,17 +351,16 @@
 	fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
 	if (fid == 0) {
-		dprintf(USB_LOG_LEVEL_ERROR, 
-				": failed to start monitoring fibril for new hub");
+		usb_log_error("failed to start monitoring fibril for new hub");
 		return ENOMEM;
 	}
 	fibril_add_ready(fid);
 
-	dprintf(USB_LOG_LEVEL_DEBUG, "hub fibril created");
+	usb_log_debug("hub fibril created");
 	//(void)hub_info;
 	//usb_hub_check_hub_changes();
 	
-	dprintf(USB_LOG_LEVEL_INFO, "hub dev added");
+	usb_log_info("hub dev added");
 	//address is lost...
-	dprintf(USB_LOG_LEVEL_DEBUG, "\taddress %d, has %d ports ",
+	usb_log_debug("\taddress %d, has %d ports ",
 			//hub_info->endpoints.control.,
 			hub_info->port_count);
@@ -379,4 +378,22 @@
 
 /**
+ * release default address used by given hub
+ *
+ * Also unsets hub->is_default_address_used. Convenience wrapper function.
+ * @note hub->connection MUST be open for communication
+ * @param hub hub representation
+ * @return error code
+ */
+static int usb_hub_release_default_address(usb_hub_info_t * hub){
+	int opResult = usb_hc_release_default_address(&hub->connection);
+	if(opResult!=EOK){
+		usb_log_error("could not release default address, errno %d",opResult);
+		return opResult;
+	}
+	hub->is_default_address_used = false;
+	return EOK;
+}
+
+/**
  * Reset the port with new device and reserve the default address.
  * @param hc
@@ -385,18 +402,25 @@
  */
 static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
-		bool isLowSpeed) {
+		usb_speed_t speed) {
+	//if this hub already uses default address, it cannot request it once more
+	if(hub->is_default_address_used) return;
+	int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
+				port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+	if(opResult != EOK){
+		usb_log_warning("could not clear port-change-connection flag");
+	}
+
 	usb_device_request_setup_packet_t request;
-	int opResult;
-	dprintf(USB_LOG_LEVEL_INFO, "some connection changed");
+	usb_log_info("some connection changed");
 	assert(hub->endpoints.control.hc_phone);
 	//get default address
-	usb_speed_t speed = isLowSpeed?USB_SPEED_LOW:USB_SPEED_FULL;
 	opResult = usb_hc_reserve_default_address(&hub->connection, speed);
 	
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_WARNING, 
-				"cannot assign default address, it is probably used %d",opResult);
-		return;
-	}
+		usb_log_warning("cannot assign default address, it is probably used %d",
+				opResult);
+		return;
+	}
+	hub->is_default_address_used = true;
 	//reset port
 	usb_hub_set_reset_port_request(&request, port);
@@ -407,9 +431,9 @@
 			);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, 
-				"something went wrong when reseting a port %d",opResult);
+		usb_log_error("something went wrong when reseting a port %d",opResult);
 		//usb_hub_release_default_address(hc);
-		usb_hc_release_default_address(&hub->connection);
-	}
+		usb_hub_release_default_address(hub);
+	}
+	return;
 }
 
@@ -424,11 +448,11 @@
 
 	int opResult;
-	dprintf(USB_LOG_LEVEL_INFO, "finalizing add device");
+	usb_log_info("finalizing add device");
 	opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
 	    port, USB_HUB_FEATURE_C_PORT_RESET);
 
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, "failed to clear port reset feature");
-		usb_hc_release_default_address(&hub->connection);
+		usb_log_error("failed to clear port reset feature");
+		usb_hub_release_default_address(hub);
 		return;
 	}
@@ -454,10 +478,10 @@
 			);
 	if (new_device_address < 0) {
-		dprintf(USB_LOG_LEVEL_ERROR, "failed to get free USB address");
+		usb_log_error("failed to get free USB address");
 		opResult = new_device_address;
-		usb_hc_release_default_address(&hub->connection);
-		return;
-	}
-	dprintf(USB_LOG_LEVEL_INFO, "setting new address %d",new_device_address);
+		usb_hub_release_default_address(hub);
+		return;
+	}
+	usb_log_info("setting new address %d",new_device_address);
 	//opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
 	//    new_device_address);
@@ -466,7 +490,6 @@
 	usb_endpoint_pipe_end_session(&new_device_pipe);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, 
-				"could not set address for new device %d",opResult);
-		usb_hc_release_default_address(&hub->connection);
+		usb_log_error("could not set address for new device %d",opResult);
+		usb_hub_release_default_address(hub);
 		return;
 	}
@@ -474,5 +497,5 @@
 
 	//opResult = usb_hub_release_default_address(hc);
-	opResult = usb_hc_release_default_address(&hub->connection);
+	opResult = usb_hub_release_default_address(hub);
 	if(opResult!=EOK){
 		return;
@@ -486,6 +509,5 @@
 
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, 
-				"could not start driver for new device %d",opResult);
+		usb_log_error("could not start driver for new device %d",opResult);
 		return;
 	}
@@ -498,9 +520,8 @@
 			&hub->attached_devs[port]);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, 
-				"could not assign address of device in hcd %d",opResult);
-		return;
-	}
-	dprintf(USB_LOG_LEVEL_INFO, "new device address %d, handle %zu",
+		usb_log_error("could not assign address of device in hcd %d",opResult);
+		return;
+	}
+	usb_log_info("new device address %d, handle %zu",
 	    new_device_address, child_handle);
 
@@ -515,5 +536,10 @@
 static void usb_hub_removed_device(
     usb_hub_info_t * hub,uint16_t port) {
-		
+
+	int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
+				port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+	if(opResult != EOK){
+		usb_log_warning("could not clear port-change-connection flag");
+	}
 	/** \TODO remove device from device manager - not yet implemented in
 	 * devide manager
@@ -533,14 +559,13 @@
 		 */
 	}else{
-		dprintf(USB_LOG_LEVEL_WARNING, "this is strange, disconnected device had no address");
+		usb_log_warning("this is strange, disconnected device had no address");
 		//device was disconnected before it`s port was reset - return default address
-		//usb_drv_release_default_address(hc);
-		usb_hc_release_default_address(&hub->connection);
-	}
-}
-
-
-/**
- *Process over current condition on port.
+		usb_hub_release_default_address(hub);
+	}
+}
+
+
+/**
+ * Process over current condition on port.
  * 
  * Turn off the power on the port.
@@ -555,5 +580,5 @@
 	    port, USB_HUB_FEATURE_PORT_POWER);
 	if(opResult!=EOK){
-		dprintf(USB_LOG_LEVEL_ERROR, "cannot power off port %d;  %d",
+		usb_log_error("cannot power off port %d;  %d",
 				port, opResult);
 	}
@@ -568,5 +593,5 @@
 static void usb_hub_process_interrupt(usb_hub_info_t * hub, 
         uint16_t port) {
-	dprintf(USB_LOG_LEVEL_DEBUG, "interrupt at port %d", port);
+	usb_log_debug("interrupt at port %d", port);
 	//determine type of change
 	usb_endpoint_pipe_t *pipe = &hub->endpoints.control;
@@ -587,19 +612,16 @@
 			);
 	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR, "could not get port status");
+		usb_log_error("could not get port status");
 		return;
 	}
 	if (rcvd_size != sizeof (usb_port_status_t)) {
-		dprintf(USB_LOG_LEVEL_ERROR, "received status has incorrect size");
+		usb_log_error("received status has incorrect size");
 		return;
 	}
 	//something connected/disconnected
 	if (usb_port_connect_change(&status)) {
-		opResult = usb_hub_clear_port_feature(pipe,
-		    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
-		// TODO: check opResult
 		if (usb_port_dev_connected(&status)) {
-			dprintf(USB_LOG_LEVEL_INFO, "some connection changed");
-			usb_hub_init_add_device(hub, port, usb_port_low_speed(&status));
+			usb_log_info("some connection changed");
+			usb_hub_init_add_device(hub, port, usb_port_speed(&status));
 		} else {
 			usb_hub_removed_device(hub, port);
@@ -612,15 +634,15 @@
 			usb_hub_over_current(hub,port);
 		}else{
-			dprintf(USB_LOG_LEVEL_INFO,
-				"over current condition was auto-resolved on port %d",port);
+			usb_log_info("over current condition was auto-resolved on port %d",
+					port);
 		}
 	}
 	//port reset
 	if (usb_port_reset_completed(&status)) {
-		dprintf(USB_LOG_LEVEL_INFO, "port reset complete");
+		usb_log_info("port reset complete");
 		if (usb_port_enabled(&status)) {
 			usb_hub_finalize_add_device(hub, port, usb_port_low_speed(&status));
 		} else {
-			dprintf(USB_LOG_LEVEL_WARNING, "port reset, but port still not enabled");
+			usb_log_warning("port reset, but port still not enabled");
 		}
 	}
@@ -631,8 +653,9 @@
 	usb_port_set_dev_connected(&status, false);
 	if (status>>16) {
-		dprintf(USB_LOG_LEVEL_INFO, "there was some unsupported change on port %d: %X",port,status);
-
-	}
-	/// \TODO handle other changes
+		usb_log_info("there was some unsupported change on port %d: %X",
+				port,status);
+
+	}
+	/// \TODO handle other changes - is there any?
 }
 
@@ -647,6 +670,6 @@
 	opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.status_change);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"could not initialize communication for hub; %d", opResult);
+		usb_log_error("could not initialize communication for hub; %d",
+				opResult);
 		return opResult;
 	}
@@ -669,5 +692,5 @@
 	if (opResult != EOK) {
 		free(change_bitmap);
-		dprintf(USB_LOG_LEVEL_WARNING, "something went wrong while getting status of hub");
+		usb_log_warning("something went wrong while getting status of hub");
 		usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
 		return opResult;
@@ -676,6 +699,5 @@
 	opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
 	if(opResult!=EOK){
-		dprintf(USB_LOG_LEVEL_ERROR, "could not start control pipe session %d",
-				opResult);
+		usb_log_error("could not start control pipe session %d", opResult);
 		usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
 		return opResult;
@@ -683,5 +705,5 @@
 	opResult = usb_hc_connection_open(&hub_info->connection);
 	if(opResult!=EOK){
-		dprintf(USB_LOG_LEVEL_ERROR, "could not start host controller session %d",
+		usb_log_error("could not start host controller session %d",
 				opResult);
 		usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/drv/usbhub/usbhub.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -71,4 +71,6 @@
 	/** hub endpoints */
 	usb_hub_endpoints_t endpoints;
+
+	bool is_default_address_used;
 } usb_hub_info_t;
 
Index: uspace/lib/usb/include/usb/classes/hid_report_items.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid_report_items.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
+++ uspace/lib/usb/include/usb/classes/hid_report_items.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * 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.
+ */
+
+/** @addtogroup libusb
+ * @{
+ */
+/** @file
+ * @brief USB HID parser.
+ */
+#ifndef LIBUSB_HID_REPORT_ITEMS_H_
+#define LIBUSB_HID_REPORT_ITEMS_H_
+
+#include <stdint.h>
+
+/* MAIN ITEMS */
+#define USB_HID_TAG_CLASS_MAIN				0x0
+#define USB_HID_REPORT_TAG_INPUT			0x8
+#define USB_HID_REPORT_TAG_OUTPUT			0x9
+#define USB_HID_REPORT_TAG_FEATURE			0xB
+#define USB_HID_REPORT_TAG_COLLECTION		0xA
+#define USB_HID_REPORT_TAG_END_COLLECTION	0xC
+
+/* GLOBAL ITEMS */
+#define USB_HID_TAG_CLASS_GLOBAL			0x1
+#define USB_HID_REPORT_TAG_USAGE_PAGE		0x0
+#define USB_HID_REPORT_TAG_LOGICAL_MINIMUM	0x1
+#define USB_HID_REPORT_TAG_LOGICAL_MAXIMUM	0x2
+#define USB_HID_REPORT_TAG_PHYSICAL_MINIMUM 0x3
+#define USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM 0x4
+#define USB_HID_REPORT_TAG_UNIT_EXPONENT	0x5
+#define USB_HID_REPORT_TAG_UNIT				0x6
+#define USB_HID_REPORT_TAG_REPORT_SIZE		0x7
+#define USB_HID_REPORT_TAG_REPORT_ID		0x8
+#define USB_HID_REPORT_TAG_REPORT_COUNT		0x9
+#define USB_HID_REPORT_TAG_PUSH				0xA
+#define USB_HID_REPORT_TAG_POP				0xB
+
+
+/* LOCAL ITEMS */
+#define USB_HID_TAG_CLASS_LOCAL					0x2
+#define USB_HID_REPORT_TAG_USAGE				0x0
+#define USB_HID_REPORT_TAG_USAGE_MINIMUM		0x1
+#define USB_HID_REPORT_TAG_USAGE_MAXIMUM		0x2
+#define USB_HID_REPORT_TAG_DESIGNATOR_INDEX		0x3
+#define USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM	0x4
+#define USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM	0x5
+#define USB_HID_REPORT_TAG_STRING_INDEX			0x7
+#define USB_HID_REPORT_TAG_STRING_MINIMUM		0x8
+#define USB_HID_REPORT_TAG_STRING_MAXIMUM		0x9
+#define USB_HID_REPORT_TAG_DELIMITER			0xA
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -37,4 +37,40 @@
 
 #include <stdint.h>
+#include <adt/list.h>
+#include <usb/classes/hid_report_items.h>
+
+/**
+ * Item prefix
+ */
+#define USB_HID_ITEM_SIZE(data) 	((uint8_t)(data & 0x3))
+#define USB_HID_ITEM_TAG(data) 		((uint8_t)((data & 0xF0) >> 4))
+#define USB_HID_ITEM_TAG_CLASS(data)	((uint8_t)((data & 0xC) >> 2))
+#define USB_HID_ITEM_IS_LONG(data)	(data == 0xFE)
+
+
+/**
+ * Input/Output/Feature Item flags
+ */
+/** Constant (1) / Variable (0) */
+#define USB_HID_ITEM_FLAG_CONSTANT(flags) 	((flags & 0x1) == 0x1)
+/** Variable (1) / Array (0) */
+#define USB_HID_ITEM_FLAG_VARIABLE(flags) 	((flags & 0x2) == 0x2)
+/** Absolute / Relative*/
+#define USB_HID_ITEM_FLAG_RELATIVE(flags) 	((flags & 0x4) == 0x4)
+/** Wrap / No Wrap */
+#define USB_HID_ITEM_FLAG_WRAP(flags)		((flags & 0x8) == 0x8)
+#define USB_HID_ITEM_FLAG_LINEAR(flags)		((flags & 0x10) == 0x10)
+#define USB_HID_ITEM_FLAG_PREFERRED(flags)	((flags & 0x20) == 0x20)
+#define USB_HID_ITEM_FLAG_POSITION(flags)	((flags & 0x40) == 0x40)
+#define USB_HID_ITEM_FLAG_VOLATILE(flags)	((flags & 0x80) == 0x80)
+#define USB_HID_ITEM_FLAG_BUFFERED(flags)	((flags & 0x100) == 0x100)
+
+
+/**
+ * Description of path of usage pages and usages in report descriptor
+ */
+typedef struct {
+	int32_t usage_page;
+} usb_hid_report_path_t;
 
 /**
@@ -42,19 +78,44 @@
  */
 typedef struct {
-
-	uint8_t usage_min;
-	uint8_t usage_max;
-	uint8_t logical_min;
-	uint8_t logical_max;
-	uint8_t size;
-	uint8_t count;
-	uint8_t offset;
-
+	int32_t id;
+	int32_t usage_page;
+	int32_t	usage;	
+	int32_t usage_minimum;
+	int32_t usage_maximum;
+	int32_t logical_minimum;
+	int32_t logical_maximum;
+	int32_t size;
+	int32_t count;
+	size_t offset;
+	int32_t delimiter;
+
+	int32_t unit_exponent;
+	int32_t unit;
+
+	/*
+	 * some not yet used fields
+	 */
+	int32_t string_index;
+	int32_t string_minimum;
+	int32_t string_maximum;
+	int32_t designator_index;
+	int32_t designator_minimum;
+	int32_t designator_maximum;
+	int32_t physical_minimum;
+	int32_t physical_maximum;
+
+	uint8_t item_flags;
+
+	link_t link;
 } usb_hid_report_item_t;
 
 
 /** HID report parser structure. */
-typedef struct {
-} usb_hid_report_parser_t;
+typedef struct {	
+	link_t input;
+	link_t output;
+	link_t feature;
+} usb_hid_report_parser_t;	
+
 
 
@@ -127,4 +188,5 @@
 int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size);
 
+int usb_hid_parser_init(usb_hid_report_parser_t *parser);
 int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
     const uint8_t *data, size_t size);
@@ -134,6 +196,11 @@
     const usb_hid_report_in_callbacks_t *callbacks, void *arg);
 
-
-int usb_hid_free_report_parser(usb_hid_report_parser_t *parser);
+int usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
+	const usb_hid_report_path_t *path);
+
+
+void usb_hid_free_report_parser(usb_hid_report_parser_t *parser);
+
+void usb_hid_descriptor_print(usb_hid_report_parser_t *parser);
 
 #endif
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/lib/usb/src/hidparser.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -36,4 +36,62 @@
 #include <errno.h>
 #include <stdio.h>
+#include <malloc.h>
+#include <mem.h>
+#include <usb/debug.h>
+
+#define USB_HID_NEW_REPORT_ITEM 1
+#define USB_HID_NO_ACTION		2
+#define USB_HID_UNKNOWN_TAG		-99
+
+#define BAD_HACK_USAGE_PAGE		0x07
+
+int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item);
+int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item);
+int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item);
+int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item);
+
+void usb_hid_descriptor_print_list(link_t *head);
+int usb_hid_report_reset_local_items();
+void usb_hid_free_report_list(link_t *head);
+int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);
+inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
+int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j);
+int usb_pow(int a, int b);
+
+int usb_pow(int a, int b)
+{
+	switch(b) {
+		case 0:
+			return 1;
+			break;
+		case 1:
+			return a;
+			break;
+		default:
+			return a * usb_pow(a, b-1);
+			break;
+	}
+}
+
+/**
+ *
+ */
+int usb_hid_parser_init(usb_hid_report_parser_t *parser)
+{
+   if(parser == NULL) {
+	return -1;
+   }
+
+    list_initialize(&(parser->input));
+    list_initialize(&(parser->output));
+    list_initialize(&(parser->feature));
+
+    return EOK;   
+}
+
 
 /** Parse HID report descriptor.
@@ -46,5 +104,486 @@
     const uint8_t *data, size_t size)
 {
-	return ENOTSUP;
+	size_t i=0;
+	uint8_t tag=0;
+	uint8_t item_size=0;
+	int class=0;
+	int ret;
+	usb_hid_report_item_t *report_item=0;
+	usb_hid_report_item_t *new_report_item;
+
+	size_t offset_input=0;
+	size_t offset_output=0;
+	size_t offset_feature=0;
+	
+
+	if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
+		return ENOMEM;
+	}
+	memset(report_item, 0, sizeof(usb_hid_report_item_t));
+	
+	link_initialize(&(report_item->link));	
+
+	while(i<size){	
+		if(!USB_HID_ITEM_IS_LONG(data[i])){
+
+			if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
+				return -1; // TODO ERROR CODE
+			}
+			
+			tag = USB_HID_ITEM_TAG(data[i]);
+			item_size = USB_HID_ITEM_SIZE(data[i]);
+			class = USB_HID_ITEM_TAG_CLASS(data[i]);
+
+			usb_log_debug2(
+				"i(%u) data(%X) value(%X): TAG %u, class %u, size %u - ", i, 
+			    data[i], usb_hid_report_tag_data_int32(data+i+1,item_size), 
+			    tag, class, item_size);
+			
+			ret = usb_hid_report_parse_tag(tag,class,data+i+1,
+			                         item_size,report_item);
+			usb_log_debug2("ret: %u\n", ret);
+			switch(ret){
+				case USB_HID_NEW_REPORT_ITEM:
+					// store report item to report and create the new one
+					usb_log_debug("\nNEW REPORT ITEM: %X",tag);
+					
+					switch(tag) {
+						case USB_HID_REPORT_TAG_INPUT:
+							report_item->offset = offset_input;
+							offset_input += report_item->count * report_item->size;
+							usb_log_debug(" - INPUT\n");
+							list_append(&(report_item->link), &(parser->input));
+							break;
+						case USB_HID_REPORT_TAG_OUTPUT:
+							report_item->offset = offset_output;
+							offset_output += report_item->count * report_item->size;
+							usb_log_debug(" - OUTPUT\n");
+								list_append(&(report_item->link), &(parser->output));
+
+							break;
+						case USB_HID_REPORT_TAG_FEATURE:
+							report_item->offset = offset_feature;
+							offset_feature += report_item->count * report_item->size;
+							usb_log_debug(" - FEATURE\n");
+								list_append(&(report_item->link), &(parser->feature));
+							break;
+						default:
+						    usb_log_debug("\tjump over - tag %X\n", tag);
+						    break;
+					}
+
+					/* clone current state table to the new item */
+					if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
+						return ENOMEM;
+					}
+					memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t));
+					/* reset local items */
+					new_report_item->usage_minimum = 0;
+					new_report_item->usage_maximum = 0;
+					
+					link_initialize(&(new_report_item->link));
+					report_item = new_report_item;
+					
+					break;
+				case USB_HID_REPORT_TAG_PUSH:
+					// push current state to stack
+					// not yet implemented
+					break;
+				case USB_HID_REPORT_TAG_POP:
+					// restore current state from stack
+					// not yet implemented						   
+					break;
+					
+				default:
+					// nothing special to do					
+					break;
+			}
+
+			/* jump over the processed block */
+			i += 1 + USB_HID_ITEM_SIZE(data[i]);
+		}
+		else{
+			// TBD
+			i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
+		}
+		
+
+	}
+	
+	return EOK;
+}
+
+
+/**
+ * Parse input report.
+ *
+ * @param data Data for report
+ * @param size Size of report
+ * @param callbacks Callbacks for report actions
+ * @param arg Custom arguments
+ *
+ * @return Error code
+ */
+int usb_hid_boot_keyboard_input_report(const uint8_t *data, size_t size,
+	const usb_hid_report_in_callbacks_t *callbacks, void *arg)
+{
+	int i;
+	usb_hid_report_item_t item;
+
+	/* fill item due to the boot protocol report descriptor */
+	// modifier keys are in the first byte
+	uint8_t modifiers = data[0];
+
+	item.offset = 2; /* second byte is reserved */
+	item.size = 8;
+	item.count = 6;
+	item.usage_minimum = 0;
+	item.usage_maximum = 255;
+	item.logical_minimum = 0;
+	item.logical_maximum = 255;
+
+	if (size != 8) {
+		return -1; //ERANGE;
+	}
+
+	uint8_t keys[6];
+	for (i = 0; i < item.count; i++) {
+		keys[i] = data[i + item.offset];
+	}
+
+	callbacks->keyboard(keys, 6, modifiers, arg);
+	return EOK;
+}
+
+/**
+ * Makes output report for keyboard boot protocol
+ *
+ * @param leds
+ * @param output Output report data buffer
+ * @param size Size of the output buffer
+ * @return Error code
+ */
+int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size)
+{
+	if(size != 1){
+		return -1;
+	}
+
+	/* used only first five bits, others are only padding*/
+	*data = leds;
+	return EOK;
+}
+
+/**
+ *
+ * @param Tag to parse
+ * @param Report descriptor buffer
+ * @param Size of data belongs to this tag
+ * @param Current report item structe
+ * @return Code of action to be done next
+ */
+int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item)
+{	
+	int ret;
+	
+	switch(class){
+		case USB_HID_TAG_CLASS_MAIN:
+
+			if((ret=usb_hid_report_parse_main_tag(tag,data,item_size,report_item)) == EOK) {
+				return USB_HID_NEW_REPORT_ITEM;
+			}
+			else {
+				/*TODO process the error */
+				return ret;
+			   }
+			break;
+
+		case USB_HID_TAG_CLASS_GLOBAL:	
+			return usb_hid_report_parse_global_tag(tag,data,item_size,report_item);
+			break;
+
+		case USB_HID_TAG_CLASS_LOCAL:			
+			return usb_hid_report_parse_local_tag(tag,data,item_size,report_item);
+			break;
+		default:
+			return USB_HID_NO_ACTION;
+	}
+}
+
+/**
+ * Parse main tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+
+int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item)
+{
+	switch(tag)
+	{
+		case USB_HID_REPORT_TAG_INPUT:
+		case USB_HID_REPORT_TAG_OUTPUT:
+		case USB_HID_REPORT_TAG_FEATURE:
+			report_item->item_flags = *data;			
+			return EOK;			
+			break;
+			
+		case USB_HID_REPORT_TAG_COLLECTION:
+			// TODO
+			return USB_HID_NO_ACTION;
+			break;
+			
+		case USB_HID_REPORT_TAG_END_COLLECTION:
+			/* should be ignored */
+			return USB_HID_NO_ACTION;
+			break;
+		default:
+			return USB_HID_NO_ACTION;
+	}
+
+	return EOK;
+}
+
+/**
+ * Parse global tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+
+int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item)
+{
+	// TODO take care about the bit length of data
+	switch(tag)
+	{
+		case USB_HID_REPORT_TAG_USAGE_PAGE:
+			report_item->usage_page = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
+			report_item->logical_minimum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
+			report_item->logical_maximum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
+			report_item->physical_minimum = usb_hid_report_tag_data_int32(data,item_size);
+			break;			
+		case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
+			report_item->physical_maximum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_UNIT_EXPONENT:
+			report_item->unit_exponent = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_UNIT:
+			report_item->unit = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_REPORT_SIZE:
+			report_item->size = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_REPORT_COUNT:
+			report_item->count = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_REPORT_ID:
+			report_item->id = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_PUSH:
+		case USB_HID_REPORT_TAG_POP:
+			return tag;
+			break;
+			
+		default:
+			return USB_HID_NO_ACTION;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Parse local tags of report descriptor
+ *
+ * @param Tag identifier
+ * @param Data buffer
+ * @param Length of data buffer
+ * @param Current state table
+ * @return Error code
+ */
+int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
+                             usb_hid_report_item_t *report_item)
+{
+	switch(tag)
+	{
+		case USB_HID_REPORT_TAG_USAGE:
+			report_item->usage = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_USAGE_MINIMUM:
+			report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
+			report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
+			report_item->designator_index = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
+			report_item->designator_minimum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
+			report_item->designator_maximum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_STRING_INDEX:
+			report_item->string_index = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_STRING_MINIMUM:
+			report_item->string_minimum = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		case USB_HID_REPORT_TAG_STRING_MAXIMUM:
+			report_item->string_maximum = usb_hid_report_tag_data_int32(data,item_size);
+			break;			
+		case USB_HID_REPORT_TAG_DELIMITER:
+			report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);
+			break;
+		
+		default:
+			return USB_HID_NO_ACTION;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Converts raw data to int32 (thats the maximum length of short item data)
+ *
+ * @param Data buffer
+ * @param Size of buffer
+ * @return Converted int32 number
+ */
+int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size)
+{
+	unsigned int i;
+	int32_t result;
+
+	result = 0;
+	for(i=0; i<size; i++) {
+		result = (result | (data[i]) << (i*8));
+	}
+
+	return result;
+}
+
+
+
+/**
+ * Prints content of given list of report items.
+ *
+ * @param List of report items
+ * @return void
+ */
+void usb_hid_descriptor_print_list(link_t *head)
+{
+	usb_hid_report_item_t *report_item;
+	link_t *item;
+	
+	if(head == NULL || list_empty(head)) {
+	    usb_log_debug("\tempty\n");
+	    return;
+	}
+        
+	for(item = head->next; item != head; item = item->next) {
+                
+		report_item = list_get_instance(item, usb_hid_report_item_t, link);
+
+		usb_log_debug("\tOFFSET: %X\n", report_item->offset);
+		usb_log_debug("\tCOUNT: %X\n", report_item->count);
+		usb_log_debug("\tSIZE: %X\n", report_item->size);
+		usb_log_debug("\tCONSTANT/VAR: %X\n", USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags));
+		usb_log_debug("\tVARIABLE/ARRAY: %X\n", USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags));
+		usb_log_debug("\tUSAGE: %X\n", report_item->usage);
+		usb_log_debug("\tUSAGE PAGE: %X\n", report_item->usage_page);
+		usb_log_debug("\tLOGMIN: %X\n", report_item->logical_minimum);
+		usb_log_debug("\tLOGMAX: %X\n", report_item->logical_maximum);		
+		usb_log_debug("\tPHYMIN: %X\n", report_item->physical_minimum);		
+		usb_log_debug("\tPHYMAX: %X\n", report_item->physical_maximum);				
+		usb_log_debug("\tUSAGEMIN: %X\n", report_item->usage_minimum);
+		usb_log_debug("\tUSAGEMAX: %X\n", report_item->usage_maximum);
+		
+		usb_log_debug("\n");		
+
+	}
+
+
+}
+/**
+ * Prints content of given descriptor in human readable format.
+ *
+ * @param Parsed descriptor to print
+ * @return void
+ */
+void usb_hid_descriptor_print(usb_hid_report_parser_t *parser)
+{
+	usb_log_debug("INPUT:\n");
+	usb_hid_descriptor_print_list(&parser->input);
+	
+	usb_log_debug("OUTPUT: \n");
+	usb_hid_descriptor_print_list(&parser->output);
+	
+	usb_log_debug("FEATURE:\n");	
+	usb_hid_descriptor_print_list(&parser->feature);
+
+}
+
+/**
+ * Releases whole linked list of report items
+ *
+ * 
+ */
+void usb_hid_free_report_list(link_t *head)
+{
+	return; 
+	
+	usb_hid_report_item_t *report_item;
+	link_t *next;
+	
+	if(head == NULL || list_empty(head)) {		
+	    return;
+	}
+	
+	next = head->next;
+	while(next != head) {
+	
+	    report_item = list_get_instance(next, usb_hid_report_item_t, link);
+	    next = next->next;
+	    
+	    free(report_item);
+	}
+	
+	return;
+	
+}
+
+/** Free the HID report parser structure 
+ *
+ * @param parser Opaque HID report parser structure
+ * @return Error code
+ */
+void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
+{
+	if(parser == NULL){
+		return;
+	}
+
+	usb_hid_free_report_list(&parser->input);
+	usb_hid_free_report_list(&parser->output);
+	usb_hid_free_report_list(&parser->feature);
+
+	return;
 }
 
@@ -58,97 +597,164 @@
  * @param arg Custom argument (passed through to the callbacks).
  * @return Error code.
- */
+ */ 
 int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
     const uint8_t *data, size_t size,
     const usb_hid_report_in_callbacks_t *callbacks, void *arg)
 {
-	int i;
-	
-	/* main parsing loop */
-	while(0){
-	}
-	
-	
-	uint8_t keys[6];
-	
-	for (i = 0; i < 6; ++i) {
-		keys[i] = data[i];
-	}
-	
-	callbacks->keyboard(keys, 6, 0, arg);
-
+	/*
+	 *
+	 * only key codes (usage page 0x07) will be processed
+	 * other usages will be ignored 
+	 */
+	link_t *list_item;
+	usb_hid_report_item_t *item;
+	uint8_t *keys;
+	uint8_t item_value;
+	size_t key_count=0;
+	size_t i=0;
+	size_t j=0;
+
+	// get the size of result keycodes array
+	usb_hid_report_path_t path;
+	path.usage_page = BAD_HACK_USAGE_PAGE;
+	key_count = usb_hid_report_input_length(parser, &path);
+
+	if(!(keys = malloc(sizeof(uint8_t) * key_count))){
+		return ENOMEM;
+	}
+
+	// read data		
+	list_item = parser->input.next;	   
+	while(list_item != &(parser->input)) {
+
+		item = list_get_instance(list_item, usb_hid_report_item_t, link);
+		if(!USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) &&
+		   (item->usage_page == path.usage_page)) {
+			for(j=0; j<(size_t)(item->count); j++) {
+				if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) ||
+				   ((item->usage_minimum == 0) && (item->usage_maximum == 0))) {
+					// variable item
+					keys[i++] = usb_hid_translate_data(item, data,j);
+				}
+				else {
+					// bitmapa
+					if((item_value = usb_hid_translate_data(item, data, j)) != 0) {
+						keys[i++] = j + item->usage_minimum;
+					}
+					else {
+						keys[i++] = 0;
+					}
+				}
+			}
+		}
+		list_item = list_item->next;
+	}
+
+	callbacks->keyboard(keys, key_count, 0, arg);
+	   
+	free(keys);	
 	return EOK;
-}
-
-/** Free the HID report parser structure 
- *
- * @param parser Opaque HID report parser structure
- * @return Error code
- */
-int usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
-{
-
-	return EOK;
-}
-
-
-/**
- * Parse input report.
- *
- * @param data Data for report
- * @param size Size of report
- * @param callbacks Callbacks for report actions
- * @param arg Custom arguments
- *
- * @return Error code
- */
-int usb_hid_boot_keyboard_input_report(const uint8_t *data, size_t size,
-	const usb_hid_report_in_callbacks_t *callbacks, void *arg)
-{
-	int i;
-	usb_hid_report_item_t item;
-
-	/* fill item due to the boot protocol report descriptor */
-	// modifier keys are in the first byte
-	uint8_t modifiers = data[0];
-
-	item.offset = 2; /* second byte is reserved */
-	item.size = 8;
-	item.count = 6;
-	item.usage_min = 0;
-	item.usage_max = 255;
-	item.logical_min = 0;
-	item.logical_max = 255;
-
-	if (size != 8) {
-		return ERANGE;
-	}
-
-	uint8_t keys[6];
-	for (i = 0; i < item.count; i++) {
-		keys[i] = data[i + item.offset];
-	}
-
-	callbacks->keyboard(keys, 6, modifiers, arg);
-	return EOK;
-}
-
-/**
- * Makes output report for keyboard boot protocol
- *
- * @param leds
- * @param output Output report data buffer
- * @param size Size of the output buffer
- * @return Error code
- */
-int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size)
-{
-	if (size < 1){
-		return -1;
-	}
-
-	data[0] = leds;
-	return EOK;
-}
+	
+}
+
+
+int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j)
+{
+	int resolution;
+	int offset;
+	int part_size;
+	
+	int32_t value;
+	int32_t mask;
+	const uint8_t *foo;
+	
+	// now only common numbers llowed
+	if(item->size > 32) {
+		return 0;
+	}
+
+	if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
+		item->physical_minimum = item->logical_minimum;
+		item->physical_maximum = item->logical_maximum;		
+	}
+
+	if(item->physical_maximum == item->physical_minimum){
+	    resolution = 1;
+	}
+	else {
+	    resolution = (item->logical_maximum - item->logical_minimum) / 
+		((item->physical_maximum - item->physical_minimum) * 
+		(usb_pow(10,(item->unit_exponent))));
+	}
+	offset = item->offset + (j * item->size);
+	
+	// FIXME
+	if((offset/8) != ((offset+item->size)/8)) {
+		usb_log_debug2("offset %d\n", offset);
+		
+		part_size = ((offset+item->size)%8);
+		usb_log_debug2("part size %d\n",part_size);
+
+		// the higher one
+		foo = data+(offset/8);
+		mask =  ((1 << (item->size-part_size))-1);
+		value = (*foo & mask) << part_size;
+
+		usb_log_debug2("hfoo %x\n", *foo);
+		usb_log_debug2("hmaska %x\n",  mask);
+		usb_log_debug2("hval %d\n", value);		
+
+		// the lower one
+		foo = data+((offset+item->size)/8);
+		mask =  ((1 << part_size)-1) << (8-part_size);
+		value += ((*foo & mask) >> (8-part_size));
+
+		usb_log_debug2("lfoo %x\n", *foo);
+		usb_log_debug2("lmaska %x\n",  mask);
+		usb_log_debug2("lval %d\n", ((*foo & mask) >> (8-(item->size-part_size))));		
+		usb_log_debug2("val %d\n", value);
+		
+		
+	}
+	else {		
+		foo = data+(offset/8);
+		mask =  ((1 << item->size)-1) << (8-((offset%8)+item->size));
+		value = (*foo & mask) >> (8-((offset%8)+item->size));
+
+		usb_log_debug2("offset %d\n", offset);
+	
+		usb_log_debug2("foo %x\n", *foo);
+		usb_log_debug2("maska %x\n",  mask);
+		usb_log_debug2("val %d\n", value);				
+	}
+
+	usb_log_debug2("---\n\n"); 
+
+	return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);
+	
+}
+
+int usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
+	const usb_hid_report_path_t *path)
+{
+	int ret = 0;
+	link_t *item;
+	usb_hid_report_item_t *report_item;
+
+	item = (&parser->input)->next;
+	while(&parser->input != item) {
+		report_item = list_get_instance(item, usb_hid_report_item_t, link);
+		if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&
+		   (report_item->usage_page == path->usage_page)) {
+			ret += report_item->count;
+		}
+
+		item = item->next;
+	} 
+
+	return ret;
+}
+
+
 
 /**
Index: uspace/srv/hid/console/gcons.c
===================================================================
--- uspace/srv/hid/console/gcons.c	(revision 054ed846de9c6f3dabfc1f854569a8bf0abe0484)
+++ uspace/srv/hid/console/gcons.c	(revision 382f32662aa02f5dcfd7631f34cc56ff47b61575)
@@ -285,6 +285,7 @@
 	ssize_t nx = (ssize_t) mouse_x + dx;
 	ssize_t ny = (ssize_t) mouse_y + dy;
-
-	if (!use_gcons)
+	
+	/* Until gcons is initalized we don't have the screen resolution */
+	if (xres == 0 || yres == 0)
 		return;
 	
