Index: uspace/app/sbi/Makefile
===================================================================
--- uspace/app/sbi/Makefile	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/Makefile	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -34,7 +34,10 @@
 
 SOURCES = \
+	src/builtin/bi_fun.c \
+	src/builtin/bi_textfile.c \
 	src/os/helenos.c \
 	src/ancr.c \
 	src/builtin.c \
+	src/imode.c \
 	src/input.c \
 	src/intmap.c \
Index: uspace/app/sbi/src/ancr.c
===================================================================
--- uspace/app/sbi/src/ancr.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/ancr.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -50,4 +50,5 @@
 #include <stdlib.h>
 #include <assert.h>
+#include "builtin.h"
 #include "list.h"
 #include "mytypes.h"
@@ -120,4 +121,5 @@
 	stree_symbol_t *base_sym;
 	stree_csi_t *base_csi, *outer_csi;
+	stree_csi_t *gf_class;
 
 	if (node->ancr_state == ws_visited) {
@@ -137,4 +139,5 @@
 
 	outer_csi = csi_to_symbol(node)->outer_csi;
+	gf_class = builtin_get_gf_class(prog->builtin);
 
 	/* Process outer CSI */
@@ -151,5 +154,9 @@
 		/* Process base CSI. */
 		ancr_csi_process(prog, base_csi);
+	} else if (node != gf_class) {
+		/* Implicit inheritance from grandfather class. */
+		base_csi = gf_class;
 	} else {
+		/* Grandfather class has no base class. */
 		base_csi = NULL;
 	}
Index: uspace/app/sbi/src/builtin.c
===================================================================
--- uspace/app/sbi/src/builtin.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/builtin.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -27,12 +27,19 @@
  */
 
-/** @file Builtin procedures. */
+/** @file Builtin symbol binding. */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
+#include "ancr.h"
+#include "builtin/bi_fun.h"
+#include "builtin/bi_textfile.h"
+#include "input.h"
+#include "intmap.h"
+#include "lex.h"
 #include "list.h"
 #include "mytypes.h"
 #include "os/os.h"
+#include "parse.h"
 #include "run.h"
 #include "stree.h"
@@ -42,16 +49,5 @@
 #include "builtin.h"
 
-static stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name);
-static void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name);
-static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name,
-    stree_texpr_t *type);
-
-static stree_texpr_t *builtin_mktype_string_array(void);
-
-static void builtin_write_line(run_t *run);
-static void builtin_exec(run_t *run);
-
-static stree_symbol_t *bi_write_line;
-static stree_symbol_t *bi_exec;
+static builtin_t *builtin_new(void);
 
 /** Declare builtin symbols in the program.
@@ -61,34 +57,122 @@
 void builtin_declare(stree_program_t *program)
 {
-	stree_modm_t *modm;
+	builtin_t *bi;
+
+	bi = builtin_new();
+	bi->program = program;
+	program->builtin = bi;
+
+	/*
+	 * Declare grandfather class.
+	 */
+
+	builtin_code_snippet(bi,
+		"class Object is\n"
+		"end\n");
+	bi->gf_class = builtin_find_lvl0(bi, "Object");
+
+	/*
+	 * Declare other builtin classes/functions.
+	 */
+
+	bi_fun_declare(bi);
+	bi_textfile_declare(bi);
+
+	/* Need to process ancestry so that symbol lookups work. */
+	ancr_module_process(program, program->module);
+
+	bi_fun_bind(bi);
+	bi_textfile_bind(bi);
+}
+
+/** Get grandfather class. */
+stree_csi_t *builtin_get_gf_class(builtin_t *builtin)
+{
+	if (builtin->gf_class == NULL)
+		return NULL;
+
+	return symbol_to_csi(builtin->gf_class);
+}
+
+static builtin_t *builtin_new(void)
+{
+	builtin_t *builtin;
+
+	builtin = calloc(1, sizeof(builtin_t));
+	if (builtin == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return builtin;
+}
+
+/** Parse a declaration code snippet.
+ *
+ * Parses a piece of code from a string at the module level. This can be
+ * used to declare builtin symbols easily and without need for an external
+ * file.
+ */
+void builtin_code_snippet(builtin_t *bi, const char *snippet)
+{
+	input_t *input;
+	lex_t lex;
+	parse_t parse;
+
+	input_new_string(&input, snippet);
+	lex_init(&lex, input);
+	parse_init(&parse, bi->program, &lex);
+	parse_module(&parse);
+}
+
+/** Simplifed search for a global symbol. */
+stree_symbol_t *builtin_find_lvl0(builtin_t *bi, const char *sym_name)
+{
+	stree_symbol_t *sym;
+	stree_ident_t *ident;
+
+	ident = stree_ident_new();
+
+	ident->sid = strtab_get_sid(sym_name);
+	sym = symbol_lookup_in_csi(bi->program, NULL, ident);
+
+	return sym;
+}
+
+/** Simplifed search for a level 1 symbol. */
+stree_symbol_t *builtin_find_lvl1(builtin_t *bi, const char *csi_name,
+    const char *sym_name)
+{
+	stree_symbol_t *csi_sym;
 	stree_csi_t *csi;
+
+	stree_symbol_t *mbr_sym;
 	stree_ident_t *ident;
-	stree_symbol_t *symbol;
 
 	ident = stree_ident_new();
-	ident->sid = strtab_get_sid("Builtin");
-
-	csi = stree_csi_new(csi_class);
-	csi->name = ident;
-	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(&program->module->members, modm);
-
-	/* Declare builtin procedures. */
-
-	bi_write_line = builtin_declare_fun(csi, "WriteLine");
-	builtin_fun_add_arg(bi_write_line, "arg");
-
-	bi_exec = builtin_declare_fun(csi, "Exec");
-	builtin_fun_add_vararg(bi_exec, "args",
-	    builtin_mktype_string_array());
+
+	ident->sid = strtab_get_sid(csi_name);
+	csi_sym = symbol_lookup_in_csi(bi->program, NULL, ident);
+	csi = symbol_to_csi(csi_sym);
+	assert(csi != NULL);
+
+	ident->sid = strtab_get_sid(sym_name);
+	mbr_sym = symbol_lookup_in_csi(bi->program, csi, ident);
+
+	return mbr_sym;
+}
+
+void builtin_fun_bind(builtin_t *bi, const char *csi_name,
+    const char *sym_name, builtin_proc_t bproc)
+{
+	stree_symbol_t *fun_sym;
+	stree_fun_t *fun;
+
+	fun_sym = builtin_find_lvl1(bi, csi_name, sym_name);
+	assert(fun_sym != NULL);
+	fun = symbol_to_fun(fun_sym);
+	assert(fun != NULL);
+
+	fun->proc->bi_handler = bproc;
 }
 
@@ -96,4 +180,6 @@
 {
 	stree_symbol_t *fun_sym;
+	builtin_t *bi;
+	builtin_proc_t bproc;
 
 #ifdef DEBUG_RUN_TRACE
@@ -101,16 +187,39 @@
 #endif
 	fun_sym = proc->outer_symbol;
-
-	if (fun_sym == bi_write_line) {
-		builtin_write_line(run);
-	} else if (fun_sym == bi_exec) {
-		builtin_exec(run);
-	} else {
-		assert(b_false);
+	bi = run->program->builtin;
+
+	bproc = proc->bi_handler;
+	if (bproc == NULL) {
+		printf("Error: Unrecognized builtin function '");
+		symbol_print_fqn(fun_sym);
+		printf("'.\n");
+		exit(1);
 	}
+
+	/* Run the builtin procedure handler. */
+	(*bproc)(run);
+}
+
+/** Get pointer to member var of current object. */
+rdata_var_t *builtin_get_self_mbr_var(run_t *run, const char *mbr_name)
+{
+	run_proc_ar_t *proc_ar;
+	rdata_object_t *object;
+	sid_t mbr_name_sid;
+	rdata_var_t *mbr_var;
+
+	proc_ar = run_get_current_proc_ar(run);
+	assert(proc_ar->obj->vc == vc_object);
+	object = proc_ar->obj->u.object_v;
+
+	mbr_name_sid = strtab_get_sid(mbr_name);
+	mbr_var = intmap_get(&object->fields, mbr_name_sid);
+	assert(mbr_var != NULL);
+
+	return mbr_var;
 }
 
 /** Declare a builtin function in @a csi. */
-static stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name)
+stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name)
 {
 	stree_ident_t *ident;
@@ -143,5 +252,5 @@
 
 /** Add one formal parameter to function. */
-static void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name)
+void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name)
 {
 	stree_proc_arg_t *proc_arg;
@@ -158,123 +267,2 @@
 	list_append(&fun->args, proc_arg);
 }
-
-/** Add variadic formal parameter to function. */
-static void builtin_fun_add_vararg(stree_symbol_t *fun_sym, const char *name,
-    stree_texpr_t *type)
-{
-	stree_proc_arg_t *proc_arg;
-	stree_fun_t *fun;
-
-	fun = symbol_to_fun(fun_sym);
-	assert(fun != NULL);
-
-	proc_arg = stree_proc_arg_new();
-	proc_arg->name = stree_ident_new();
-	proc_arg->name->sid = strtab_get_sid(name);
-	proc_arg->type = type;
-
-	fun->varg = proc_arg;
-}
-
-/** Construct a @c string[] type expression. */
-static stree_texpr_t *builtin_mktype_string_array(void)
-{
-	stree_texpr_t *tstring;
-	stree_texpr_t *tsarray;
-	stree_tliteral_t *tliteral;
-	stree_tindex_t *tindex;
-
-	/* Construct @c string */
-	tstring = stree_texpr_new(tc_tliteral);
-	tliteral = stree_tliteral_new(tlc_string);
-	tstring->u.tliteral = tliteral;
-
-	/* Construct the indexing node */
-	tsarray = stree_texpr_new(tc_tindex);
-	tindex = stree_tindex_new();
-	tsarray->u.tindex = tindex;
-
-	tindex->base_type = tstring;
-	tindex->n_args = 1;
-	list_init(&tindex->args);
-
-	return tsarray;
-}
-
-static void builtin_write_line(run_t *run)
-{
-	rdata_var_t *var;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.WriteLine()\n");
-#endif
-	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
-	assert(var);
-
-	switch (var->vc) {
-	case vc_int:
-		printf("%d\n", var->u.int_v->value);
-		break;
-	case vc_string:
-		printf("%s\n", var->u.string_v->value);
-		break;
-	default:
-		printf("Unimplemented: writeLine() with unsupported type.\n");
-		exit(1);
-	}
-}
-
-/** Start an executable and wait for it to finish. */
-static void builtin_exec(run_t *run)
-{
-	rdata_var_t *args;
-	rdata_var_t *var;
-	rdata_array_t *array;
-	rdata_var_t *arg;
-	int idx, dim;
-	char **cmd;
-
-#ifdef DEBUG_RUN_TRACE
-	printf("Called Builtin.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(cmd) != EOK) {
-		printf("Error: Exec failed.\n");
-		exit(1);
-	}
-}
Index: uspace/app/sbi/src/builtin.h
===================================================================
--- uspace/app/sbi/src/builtin.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/builtin.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -33,5 +33,20 @@
 
 void builtin_declare(stree_program_t *program);
+void builtin_code_snippet(builtin_t *bi, const char *snippet);
+
+stree_csi_t *builtin_get_gf_class(builtin_t *builtin);
 void builtin_run_proc(run_t *run, stree_proc_t *proc);
 
+rdata_var_t *builtin_get_self_mbr_var(run_t *run, const char *mbr_name);
+
+stree_symbol_t *builtin_declare_fun(stree_csi_t *csi, const char *name);
+void builtin_fun_add_arg(stree_symbol_t *fun_sym, const char *name);
+
+stree_symbol_t *builtin_find_lvl0(builtin_t *bi, const char *sym_name);
+stree_symbol_t *builtin_find_lvl1(builtin_t *bi, const char *csi_name,
+    const char *sym_name);
+
+void builtin_fun_bind(builtin_t *bi, const char *csi_name,
+    const char *sym_name, builtin_proc_t bproc);
+
 #endif
Index: uspace/app/sbi/src/builtin/bi_fun.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
+++ uspace/app/sbi/src/builtin/bi_fun.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -0,0 +1,173 @@
+/*
+ * 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 "../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_writeline(run_t *run);
+static void bi_fun_task_exec(run_t *run);
+
+/** Declare builtin functions. */
+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->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.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), builtin;\n"
+		"end\n");
+}
+
+/** Bind builtin functions. */
+void bi_fun_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "Builtin", "WriteLine", bi_fun_builtin_writeline);
+	builtin_fun_bind(bi, "Task", "Exec", bi_fun_task_exec);
+}
+
+/** Write a line of output. */
+static void bi_fun_builtin_writeline(run_t *run)
+{
+	rdata_var_t *var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called Builtin.WriteLine()\n");
+#endif
+	var = run_local_vars_lookup(run, strtab_get_sid("arg"));
+	assert(var);
+
+	switch (var->vc) {
+	case vc_int:
+		printf("%d\n", var->u.int_v->value);
+		break;
+	case vc_string:
+		printf("%s\n", var->u.string_v->value);
+		break;
+	default:
+		printf("Unimplemented: writeLine() with unsupported type.\n");
+		exit(1);
+	}
+}
+
+/** Start an executable and wait for it to finish. */
+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;
+	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(cmd) != EOK) {
+		printf("Error: Exec failed.\n");
+		exit(1);
+	}
+}
Index: uspace/app/sbi/src/builtin/bi_fun.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_fun.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
+++ uspace/app/sbi/src/builtin/bi_fun.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -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_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_textfile.c
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
+++ uspace/app/sbi/src/builtin/bi_textfile.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -0,0 +1,358 @@
+/*
+ * 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 TextFile builtin binding. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "../builtin.h"
+#include "../debug.h"
+#include "../mytypes.h"
+#include "../os/os.h"
+#include "../rdata.h"
+#include "../run.h"
+#include "../strtab.h"
+
+#include "bi_textfile.h"
+
+#define LINE_BUF_SIZE 256
+static char line_buf[LINE_BUF_SIZE];
+
+static void bi_textfile_openread(run_t *run);
+static void bi_textfile_openwrite(run_t *run);
+static void bi_textfile_close(run_t *run);
+static void bi_textfile_readline(run_t *run);
+static void bi_textfile_writeline(run_t *run);
+static void bi_textfile_is_eof(run_t *run);
+
+/** Declare TextFile builtin. */
+void bi_textfile_declare(builtin_t *bi)
+{
+	/* Declare class TextFile. */
+
+	builtin_code_snippet(bi,
+		"class TextFile is\n"
+			"var f : resource;\n"
+			"\n"
+			"fun OpenRead(fname : string), builtin;\n"
+			"fun OpenWrite(fname : string), builtin;\n"
+			"fun Close(), builtin;\n"
+			"fun ReadLine() : string, builtin;\n"
+			"fun WriteLine(line : string), builtin;\n"
+			"\n"
+			"prop EOF : int is\n"
+				"get is\n"
+					"return is_eof();\n"
+				"end\n"
+			"end\n"
+			"\n"
+			"fun is_eof() : int, builtin;\n"
+		"end\n");
+
+}
+
+/** Bind TextFile builtin. */
+void bi_textfile_bind(builtin_t *bi)
+{
+	builtin_fun_bind(bi, "TextFile", "OpenRead", bi_textfile_openread);
+	builtin_fun_bind(bi, "TextFile", "OpenWrite", bi_textfile_openwrite);
+	builtin_fun_bind(bi, "TextFile", "Close", bi_textfile_close);
+	builtin_fun_bind(bi, "TextFile", "ReadLine", bi_textfile_readline);
+	builtin_fun_bind(bi, "TextFile", "WriteLine", bi_textfile_writeline);
+	builtin_fun_bind(bi, "TextFile", "is_eof", bi_textfile_is_eof);
+}
+
+/** Open a text file for reading. */
+static void bi_textfile_openread(run_t *run)
+{
+	rdata_var_t *fname_var;
+	char *fname;
+	FILE *file;
+
+	rdata_resource_t *resource;
+	rdata_var_t *res_var;
+	rdata_value_t *res_val;
+	rdata_var_t *self_f_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called TextFile.OpenRead()\n");
+#endif
+	fname_var = run_local_vars_lookup(run, strtab_get_sid("fname"));
+	assert(fname_var);
+	assert(fname_var->vc == vc_string);
+
+	fname = fname_var->u.string_v->value;
+	file = fopen(fname, "rt");
+	if (file == NULL) {
+		printf("Error: Failed opening file '%s' for reading.\n",
+		    fname);
+		exit(1);
+	}
+
+	resource = rdata_resource_new();
+	resource->data = (void *) file;
+	res_var = rdata_var_new(vc_resource);
+	res_var->u.resource_v = resource;
+
+	res_val = rdata_value_new();
+	res_val->var = res_var;
+
+	/* Store resource handle into self.f */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	rdata_var_write(self_f_var, res_val);
+}
+
+/** Open a text file for writing. */
+static void bi_textfile_openwrite(run_t *run)
+{
+	rdata_var_t *fname_var;
+	char *fname;
+	FILE *file;
+
+	rdata_resource_t *resource;
+	rdata_var_t *res_var;
+	rdata_value_t *res_val;
+	rdata_var_t *self_f_var;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Called TextFile.OpenWrite()\n");
+#endif
+	fname_var = run_local_vars_lookup(run, strtab_get_sid("fname"));
+	assert(fname_var);
+	assert(fname_var->vc == vc_string);
+
+	fname = fname_var->u.string_v->value;
+	file = fopen(fname, "wt");
+	if (file == NULL) {
+		printf("Error: Failed opening file '%s' for writing.\n",
+		    fname);
+		exit(1);
+	}
+
+	resource = rdata_resource_new();
+	resource->data = (void *) file;
+	res_var = rdata_var_new(vc_resource);
+	res_var->u.resource_v = resource;
+
+	res_val = rdata_value_new();
+	res_val->var = res_var;
+
+	/* Store resource handle into self.f */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	rdata_var_write(self_f_var, res_val);
+}
+
+/** Close a text file. */
+static void bi_textfile_close(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+	run_proc_ar_t *proc_ar;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for Close.\n");
+		exit(1);
+	}
+
+	/* Close the file. */
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Close text file.\n");
+#endif
+	if (fclose(file) != 0) {
+		printf("Error: I/O error while closing file.\n");
+		exit(1);
+	}
+
+	/* Invalidate the resource handle. */
+	self_f_var->u.resource_v->data = NULL;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = NULL;
+}
+
+
+/** Read one line from a text file. */
+static void bi_textfile_readline(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+
+	rdata_string_t *str;
+	rdata_var_t *str_var;
+	rdata_value_t *str_val;
+	rdata_item_t *str_item;
+
+	run_proc_ar_t *proc_ar;
+	char *cp;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for ReadLine.\n");
+		exit(1);
+	}
+
+	/* Check and read. */
+
+	if (feof(file)) {
+		printf("Error: Reading beyond end of file.\n");
+		exit(1);
+	}
+
+	if (fgets(line_buf, LINE_BUF_SIZE, file) == NULL)
+		line_buf[0] = '\0';
+
+	if (ferror(file)) {
+		printf("Error: I/O error while reading file.\n");
+		exit(1);
+	}
+
+	/* Remove trailing newline, if present. */
+
+	cp = line_buf;
+	while (*cp != '\0')
+		++cp;
+
+	if (cp != line_buf && cp[-1] == '\n')
+		cp[-1] = '\0';
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read '%s' from file.\n", line_buf);
+#endif
+	/* Construct return value. */
+	str = rdata_string_new();
+	str->value = os_str_dup(line_buf);
+
+	str_var = rdata_var_new(vc_string);
+	str_var->u.string_v = str;
+	str_val = rdata_value_new();
+	str_val->var = str_var;
+
+	str_item = rdata_item_new(ic_value);
+	str_item->u.value = str_val;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = str_item;
+}
+
+/** Write one line to a text file. */
+static void bi_textfile_writeline(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+	rdata_var_t *line_var;
+	char *line;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Get 'line' argument. */
+	line_var = run_local_vars_lookup(run, strtab_get_sid("line"));
+	assert(line_var);
+	assert(line_var->vc == vc_string);
+	line = line_var->u.string_v->value;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for WriteLine.\n");
+		exit(1);
+	}
+
+	/* Write and check. */
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Write '%s' to file.\n", line);
+#endif
+	if (fprintf(file, "%s\n", line) < 0) {
+		printf("Error: I/O error while writing file.\n");
+		exit(1);
+	}
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = NULL;
+}
+
+/** Return value of EOF flag. */
+static void bi_textfile_is_eof(run_t *run)
+{
+	FILE *file;
+        rdata_var_t *self_f_var;
+
+	int eof_flag;
+	rdata_int_t *eof_int;
+	rdata_var_t *eof_var;
+	rdata_value_t *eof_val;
+	rdata_item_t *eof_item;
+
+	run_proc_ar_t *proc_ar;
+
+	/* Extract pointer to file structure. */
+	self_f_var = builtin_get_self_mbr_var(run, "f");
+	assert(self_f_var->vc == vc_resource);
+	file = (FILE *) self_f_var->u.resource_v->data;
+
+	if (file == NULL) {
+		printf("Error: TextFile not valid for EOF check.\n");
+		exit(1);
+	}
+
+	/* Get status of EOF flag. */
+
+	eof_flag = feof(file) ? 1 : 0;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Read EOF flag '%d'.\n", eof_flag);
+#endif
+	/* Construct return value. */
+	eof_int = rdata_int_new();
+	eof_int->value = eof_flag;
+
+	eof_var = rdata_var_new(vc_int);
+	eof_var->u.int_v = eof_int;
+	eof_val = rdata_value_new();
+	eof_val->var = eof_var;
+
+	eof_item = rdata_item_new(ic_value);
+	eof_item->u.value = eof_val;
+
+	proc_ar = run_get_current_proc_ar(run);
+	proc_ar->retval = eof_item;
+}
Index: uspace/app/sbi/src/builtin/bi_textfile.h
===================================================================
--- uspace/app/sbi/src/builtin/bi_textfile.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
+++ uspace/app/sbi/src/builtin/bi_textfile.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -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_TEXTFILE_H_
+#define BI_TEXTFILE_H_
+
+#include "../mytypes.h"
+
+void bi_textfile_declare(builtin_t *bi);
+void bi_textfile_bind(builtin_t *bi);
+
+#endif
Index: uspace/app/sbi/src/input.c
===================================================================
--- uspace/app/sbi/src/input.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/input.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -42,8 +42,10 @@
 #define INPUT_BUFFER_SIZE 256
 
-static int input_init(input_t *input, char *fname);
+static int input_init_file(input_t *input, char *fname);
+static void input_init_interactive(input_t *input);
+static void input_init_string(input_t *input, const char *str);
 
-/** Create new input object. */
-int input_new(input_t **input, char *fname)
+/** Create new input object for reading from file. */
+int input_new_file(input_t **input, char *fname)
 {
 	*input = malloc(sizeof(input_t));
@@ -51,9 +53,31 @@
 		return ENOMEM;
 
-	return input_init(*input, fname);
+	return input_init_file(*input, fname);
 }
 
-/** Initialize input object. */
-static int input_init(input_t *input, char *fname)
+/** Create new input object for reading from interactive input. */
+int input_new_interactive(input_t **input)
+{
+	*input = malloc(sizeof(input_t));
+	if (*input == NULL)
+		return ENOMEM;
+
+	input_init_interactive(*input);
+	return EOK;
+}
+
+/** Create new input object for reading from string. */
+int input_new_string(input_t **input, const char *str)
+{
+	*input = malloc(sizeof(input_t));
+	if (*input == NULL)
+		return ENOMEM;
+
+	input_init_string(*input, str);
+	return EOK;
+}
+
+/** Initialize input object for reading from file. */
+static int input_init_file(input_t *input, char *fname)
 {
 	FILE *f;
@@ -74,14 +98,82 @@
 }
 
+/** Initialize input object for reading from interactive input. */
+static void input_init_interactive(input_t *input)
+{
+	input->buffer = malloc(INPUT_BUFFER_SIZE);
+	if (input->buffer == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	input->line_no = 0;
+	input->fin = NULL;
+}
+
+/** Initialize input object for reading from string. */
+static void input_init_string(input_t *input, const char *str)
+{
+	input->buffer = malloc(INPUT_BUFFER_SIZE);
+	if (input->buffer == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	input->str = str;
+	input->line_no = 0;
+	input->fin = NULL;
+}
+
 /** Get next line of input. */
 int input_get_line(input_t *input, char **line)
 {
-	if (fgets(input->buffer, INPUT_BUFFER_SIZE, input->fin) == NULL)
-		input->buffer[0] = '\0';
+	const char *sp;
+	char *dp;
+	size_t cnt;
 
-	if (ferror(input->fin))
-		return EIO;
+	if (input->fin != NULL) {
+		/* Reading from file. */
+		if (fgets(input->buffer, INPUT_BUFFER_SIZE, input->fin) == NULL)
+			input->buffer[0] = '\0';
 
-	*line = input->buffer;
+		if (ferror(input->fin))
+			return EIO;
+
+		*line = input->buffer;
+	} else if (input->str != NULL) {
+		/* Reading from a string constant. */
+
+		/* Copy one line. */
+		sp = input->str;
+		dp = input->buffer;
+		cnt = 0;
+		while (*sp != '\n' && *sp != '\0' &&
+		    cnt < INPUT_BUFFER_SIZE - 2) {
+			*dp++ = *sp++;
+		}
+
+		/* Advance to start of next line. */
+		if (*sp == '\n')
+			*dp++ = *sp++;
+
+		*dp++ = '\0';
+		input->str = sp;
+		*line = input->buffer;
+	} else {
+		/* Interactive mode */
+		if (input->line_no == 0)
+			printf("sbi> ");
+		else
+			printf("...  ");
+
+		if (fgets(input->buffer, INPUT_BUFFER_SIZE, stdin) == NULL)
+			input->buffer[0] = '\0';
+
+		if (ferror(stdin))
+			return EIO;
+
+		*line = input->buffer;
+	}
+
 	++input->line_no;
 	return EOK;
Index: uspace/app/sbi/src/input.h
===================================================================
--- uspace/app/sbi/src/input.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/input.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -32,5 +32,8 @@
 #include "mytypes.h"
 
-int input_new(input_t **input, char *fname);
+int input_new_file(input_t **input, char *fname);
+int input_new_interactive(input_t **input);
+int input_new_string(input_t **input, const char *str);
+
 int input_get_line(input_t *input, char **line);
 int input_get_line_no(input_t *input);
Index: uspace/app/sbi/src/input_t.h
===================================================================
--- uspace/app/sbi/src/input_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/input_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -34,8 +34,11 @@
 /** Input state object */
 typedef struct input {
-	/** Input file */
+	/** Input file if reading from file. */
 	FILE *fin;
 
-	/** Buffer holding current line */
+	/** Input string if reading from string. */
+	const char *str;
+
+	/** Buffer holding current line. */
 	char *buffer;
 
Index: uspace/app/sbi/src/lex.c
===================================================================
--- uspace/app/sbi/src/lex.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/lex.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -44,5 +44,6 @@
 #define TAB_WIDTH 8
 
-static bool_t lex_next_try(lex_t *lex);
+static void lex_touch(lex_t *lex);
+static bool_t lex_read_try(lex_t *lex);
 
 static void lex_skip_comment(lex_t *lex);
@@ -72,4 +73,6 @@
 /** Keyword names. Used both for printing and recognition. */
 static struct lc_name keywords[] = {
+	{ lc_as,	"as" },
+	{ lc_builtin,	"builtin" },
 	{ lc_class,	"class" },
 	{ lc_constructor,	"constructor" },
@@ -96,4 +99,5 @@
 	{ lc_public,	"public" },
 	{ lc_raise,	"raise" },
+	{ lc_resource,	"resource" },
 	{ lc_return,	"return" },
 	{ lc_self,	"self" },
@@ -221,14 +225,43 @@
 	lex->ibp = lex->inbuf;
 	lex->col_adj = 0;
-}
-
-/** Read next lexical element. */
+	lex->current_valid = b_true;
+}
+
+/** Advance to next lexical element.
+ *
+ * The new element be read in lazily then it is actually accessed.
+ */
 void lex_next(lex_t *lex)
 {
+	/* Make sure the current lem has already been read in. */
+	lex_touch(lex);
+
+	/* Force a new lem to be read on next access. */
+	lex->current_valid = b_false;
+}
+
+/** Get current lem.
+ *
+ * The returned pointer is invalidated by next call to lex_next()
+ */
+lem_t *lex_get_current(lex_t *lex)
+{
+	lex_touch(lex);
+	return &lex->current;
+}
+
+/** Read in the current lexical element (unless already read in). */
+static void lex_touch(lex_t *lex)
+{
 	bool_t got_lem;
 
+	if (lex->current_valid == b_true)
+		return;
+
 	do {
-		got_lem = lex_next_try(lex);
+		got_lem = lex_read_try(lex);
 	} while (got_lem == b_false);
+
+	lex->current_valid = b_true;
 }
 
@@ -237,5 +270,5 @@
  * @return @c b_true on success or @c b_false if it needs restarting.
  */
-static bool_t lex_next_try(lex_t *lex)
+static bool_t lex_read_try(lex_t *lex)
 {
 	char *bp;
Index: uspace/app/sbi/src/lex.h
===================================================================
--- uspace/app/sbi/src/lex.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/lex.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -38,4 +38,5 @@
 void lex_init(lex_t *lex, struct input *input);
 void lex_next(lex_t *lex);
+lem_t *lex_get_current(lex_t *lex);
 
 #endif
Index: uspace/app/sbi/src/lex_t.h
===================================================================
--- uspace/app/sbi/src/lex_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/lex_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -40,4 +40,6 @@
 
 	/* Keywords */
+	lc_as,
+	lc_builtin,
 	lc_class,
 	lc_constructor,
@@ -64,4 +66,5 @@
 	lc_public,
 	lc_raise,
+	lc_resource,
 	lc_return,
 	lc_self,
@@ -149,5 +152,8 @@
 	int col_adj;
 
-	/** Curent lem */
+	/** @c b_true if we have the next lem in @c current */
+	bool_t current_valid;
+
+	/** Curent lem (only valid if @c current_valid is true) */
 	lem_t current;
 } lex_t;
Index: uspace/app/sbi/src/main.c
===================================================================
--- uspace/app/sbi/src/main.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/main.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -33,4 +33,5 @@
 #include "ancr.h"
 #include "builtin.h"
+#include "imode.h"
 #include "mytypes.h"
 #include "strtab.h"
@@ -54,4 +55,11 @@
 	int rc;
 
+	if (argc == 1) {
+		/* Enter interactive mode */
+		strtab_init();
+		imode_run();
+		return 0;
+	}
+
 	if (argc != 2) {
 		syntax_print();
@@ -59,5 +67,5 @@
 	}
 
-	rc = input_new(&input, argv[1]);
+	rc = input_new_file(&input, argv[1]);
 	if (rc != EOK) {
 		printf("Failed opening source file '%s'.\n", argv[1]);
Index: uspace/app/sbi/src/mytypes.h
===================================================================
--- uspace/app/sbi/src/mytypes.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/mytypes.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -47,4 +47,5 @@
 #define EOK 0
 
+#include "builtin_t.h"
 #include "input_t.h"
 #include "intmap_t.h"
Index: uspace/app/sbi/src/p_expr.c
===================================================================
--- uspace/app/sbi/src/p_expr.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/p_expr.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -49,4 +49,5 @@
 static stree_expr_t *parse_pf_call(parse_t *parse, stree_expr_t *a);
 static stree_expr_t *parse_pf_index(parse_t *parse, stree_expr_t *a);
+static stree_expr_t *parse_pf_as(parse_t *parse, stree_expr_t *a);
 static stree_expr_t *parse_primitive(parse_t *parse);
 static stree_expr_t *parse_nameref(parse_t *parse);
@@ -206,5 +207,5 @@
 
 	while (lcur_lc(parse) == lc_period || lcur_lc(parse) == lc_lparen ||
-	    lcur_lc(parse) == lc_lsbr) {
+	    lcur_lc(parse) == lc_lsbr || lcur_lc(parse) == lc_as) {
 
 		switch (lcur_lc(parse)) {
@@ -218,4 +219,7 @@
 			tmp = parse_pf_index(parse, a);
 			break;
+		case lc_as:
+			tmp = parse_pf_as(parse, a);
+			break;
 		default:
 			assert(b_false);
@@ -316,4 +320,23 @@
 }
 
+/** Parse @c as operator. */
+static stree_expr_t *parse_pf_as(parse_t *parse, stree_expr_t *a)
+{
+	stree_expr_t *expr;
+	stree_texpr_t *texpr;
+	stree_as_t *as_op;
+
+	lmatch(parse, lc_as);
+	texpr = parse_texpr(parse);
+
+	as_op = stree_as_new();
+	as_op->arg = a;
+	as_op->dtype = texpr;
+	expr = stree_expr_new(ec_as);
+	expr->u.as_op = as_op;
+
+	return expr;
+}
+
 /** Parse primitive expression. */
 static stree_expr_t *parse_primitive(parse_t *parse)
Index: uspace/app/sbi/src/p_type.c
===================================================================
--- uspace/app/sbi/src/p_type.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/p_type.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -179,4 +179,5 @@
 	case lc_int:
 	case lc_string:
+	case lc_resource:
 		texpr = stree_texpr_new(tc_tliteral);
 		texpr->u.tliteral = parse_tliteral(parse);
@@ -203,4 +204,7 @@
 		tlc = tlc_string;
 		break;
+	case lc_resource:
+		tlc = tlc_resource;
+		break;
 	default:
 		assert(b_false);
Index: uspace/app/sbi/src/parse.c
===================================================================
--- uspace/app/sbi/src/parse.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/parse.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -43,4 +43,5 @@
 #include "stree.h"
 #include "strtab.h"
+#include "symbol.h"
 
 #include "parse.h"
@@ -49,10 +50,13 @@
  * Module members
  */
-static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass);
+static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
+    stree_csi_t *outer_csi);
 static stree_csimbr_t *parse_csimbr(parse_t *parse, stree_csi_t *outer_csi);
 
-static stree_fun_t *parse_fun(parse_t *parse);
-static stree_var_t *parse_var(parse_t *parse);
-static stree_prop_t *parse_prop(parse_t *parse);
+static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi);
+static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi);
+static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi);
+
+static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse);
 
 static stree_proc_arg_t *parse_proc_arg(parse_t *parse);
@@ -63,5 +67,4 @@
  */
 static stree_block_t *parse_block(parse_t *parse);
-static stree_stat_t *parse_stat(parse_t *parse);
 
 static stree_vdecl_t *parse_vdecl(parse_t *parse);
@@ -89,5 +92,4 @@
 	stree_csi_t *csi;
 	stree_modm_t *modm;
-	stree_symbol_t *symbol;
 
 	while (lcur_lc(parse) != lc_eof) {
@@ -96,12 +98,7 @@
 		case lc_struct:
 		case lc_interface:
-			csi = parse_csi(parse, lcur_lc(parse));
+			csi = parse_csi(parse, lcur_lc(parse), NULL);
 			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(&parse->cur_mod->members, modm);
@@ -117,9 +114,11 @@
 
 /** Parse class, struct or interface declaration. */
-static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass)
+static stree_csi_t *parse_csi(parse_t *parse, lclass_t dclass,
+    stree_csi_t *outer_csi)
 {
 	stree_csi_t *csi;
 	csi_class_t cc;
 	stree_csimbr_t *csimbr;
+	stree_symbol_t *symbol;
 
 	switch (dclass) {
@@ -134,4 +133,9 @@
 	csi = stree_csi_new(cc);
 	csi->name = parse_ident(parse);
+
+	symbol = stree_symbol_new(sc_csi);
+	symbol->u.csi = csi;
+	symbol->outer_csi = outer_csi;
+	csi->symbol = symbol;
 
 #ifdef DEBUG_PARSE_TRACE
@@ -171,53 +175,26 @@
 	stree_prop_t *prop;
 
-	stree_symbol_t *symbol;
-
 	switch (lcur_lc(parse)) {
 	case lc_class:
 	case lc_struct:
 	case lc_interface:
-		csi = parse_csi(parse, lcur_lc(parse));
+		csi = parse_csi(parse, lcur_lc(parse), outer_csi);
 		csimbr = stree_csimbr_new(csimbr_csi);
 		csimbr->u.csi = csi;
-
-		symbol = stree_symbol_new(sc_csi);
-		symbol->u.csi = csi;
-		symbol->outer_csi = outer_csi;
-		csi->symbol = symbol;
 		break;
 	case lc_fun:
-		fun = parse_fun(parse);
+		fun = parse_fun(parse, outer_csi);
 		csimbr = stree_csimbr_new(csimbr_fun);
 		csimbr->u.fun = fun;
-
-		symbol = stree_symbol_new(sc_fun);
-		symbol->u.fun = fun;
-		symbol->outer_csi = outer_csi;
-		fun->symbol = symbol;
-		fun->proc->outer_symbol = symbol;
 		break;
 	case lc_var:
-		var = parse_var(parse);
+		var = parse_var(parse, outer_csi);
 		csimbr = stree_csimbr_new(csimbr_var);
 		csimbr->u.var = var;
-
-		symbol = stree_symbol_new(sc_var);
-		symbol->u.var = var;
-		symbol->outer_csi = outer_csi;
-		var->symbol = symbol;
 		break;
 	case lc_prop:
-		prop = parse_prop(parse);
+		prop = parse_prop(parse, outer_csi);
 		csimbr = stree_csimbr_new(csimbr_prop);
 		csimbr->u.prop = prop;
-
-		symbol = stree_symbol_new(sc_prop);
-		symbol->u.prop = prop;
-		symbol->outer_csi = outer_csi;
-		prop->symbol = symbol;
-		if (prop->getter)
-			prop->getter->outer_symbol = symbol;
-		if (prop->setter)
-			prop->setter->outer_symbol = symbol;
 		break;
 	default:
@@ -231,10 +208,17 @@
 
 /** Parse member function. */
-static stree_fun_t *parse_fun(parse_t *parse)
+static stree_fun_t *parse_fun(parse_t *parse, stree_csi_t *outer_csi)
 {
 	stree_fun_t *fun;
 	stree_proc_arg_t *arg;
+	stree_symbol_t *symbol;
+	stree_symbol_attr_t *attr;
 
 	fun = stree_fun_new();
+	symbol = stree_symbol_new(sc_fun);
+
+	symbol->u.fun = fun;
+	symbol->outer_csi = outer_csi;
+	fun->symbol = symbol;
 
 	lmatch(parse, lc_fun);
@@ -277,8 +261,32 @@
 	}
 
-	lmatch(parse, lc_is);
+	list_init(&symbol->attr);
+
+	/* Parse attributes. */
+	while (lcur_lc(parse) == lc_comma) {
+		lskip(parse);
+		attr = parse_symbol_attr(parse);
+		list_append(&symbol->attr, attr);
+	}
+
 	fun->proc = stree_proc_new();
-	fun->proc->body = parse_block(parse);
-	lmatch(parse, lc_end);
+	fun->proc->outer_symbol = symbol;
+
+	if (lcur_lc(parse) == lc_scolon) {
+		lskip(parse);
+
+		/* This function has no body. */
+		if (!stree_symbol_has_attr(symbol, sac_builtin)) {
+			printf("Error: Function '");
+			symbol_print_fqn(symbol);
+			printf("' has no body.\n");
+			exit(1);
+		}
+		fun->proc->body = NULL;
+	} else {
+		lmatch(parse, lc_is);
+		fun->proc->body = parse_block(parse);
+		lmatch(parse, lc_end);
+	}
 
 	return fun;
@@ -286,9 +294,14 @@
 
 /** Parse member variable. */
-static stree_var_t *parse_var(parse_t *parse)
+static stree_var_t *parse_var(parse_t *parse, stree_csi_t *outer_csi)
 {
 	stree_var_t *var;
+	stree_symbol_t *symbol;
 
 	var = stree_var_new();
+	symbol = stree_symbol_new(sc_var);
+	symbol->u.var = var;
+	symbol->outer_csi = outer_csi;
+	var->symbol = symbol;
 
 	lmatch(parse, lc_var);
@@ -302,7 +315,9 @@
 
 /** Parse member property. */
-static stree_prop_t *parse_prop(parse_t *parse)
+static stree_prop_t *parse_prop(parse_t *parse, stree_csi_t *outer_csi)
 {
 	stree_prop_t *prop;
+	stree_symbol_t *symbol;
+
 	stree_ident_t *ident;
 	stree_proc_arg_t *arg;
@@ -310,4 +325,9 @@
 	prop = stree_prop_new();
 	list_init(&prop->args);
+
+	symbol = stree_symbol_new(sc_prop);
+	symbol->u.prop = prop;
+	symbol->outer_csi = outer_csi;
+	prop->symbol = symbol;
 
 	lmatch(parse, lc_prop);
@@ -363,4 +383,5 @@
 			prop->getter = stree_proc_new();
 			prop->getter->body = parse_block(parse);
+			prop->getter->outer_symbol = symbol;
 
 			lmatch(parse, lc_end);
@@ -380,4 +401,5 @@
 			prop->setter = stree_proc_new();
 			prop->setter->body = parse_block(parse);
+			prop->setter->outer_symbol = symbol;
 
 			lmatch(parse, lc_end);
@@ -393,4 +415,22 @@
 }
 
+/** Parse symbol attribute. */
+static stree_symbol_attr_t *parse_symbol_attr(parse_t *parse)
+{
+	stree_symbol_attr_t *attr;
+
+	if (lcur_lc(parse) != lc_builtin) {
+		printf("Error: Unexpected attribute '");
+		lem_print(lcur(parse));
+		printf("'.\n");
+		exit(1);
+	}
+
+	lskip(parse);
+
+	attr = stree_symbol_attr_new(sac_builtin);
+	return attr;
+}
+
 /** Parse formal function argument. */
 static stree_proc_arg_t *parse_proc_arg(parse_t *parse)
@@ -455,5 +495,5 @@
 
 /** Parse statement. */
-static stree_stat_t *parse_stat(parse_t *parse)
+stree_stat_t *parse_stat(parse_t *parse)
 {
 	stree_stat_t *stat;
@@ -719,5 +759,5 @@
 lem_t *lcur(parse_t *parse)
 {
-	return &parse->lex->current;
+	return lex_get_current(parse->lex);
 }
 
@@ -725,5 +765,8 @@
 lclass_t lcur_lc(parse_t *parse)
 {
-	return parse->lex->current.lclass;
+	lem_t *lem;
+
+	lem = lcur(parse);
+	return lem->lclass;
 }
 
Index: uspace/app/sbi/src/parse.h
===================================================================
--- uspace/app/sbi/src/parse.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/parse.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -35,4 +35,5 @@
 void parse_module(parse_t *parse);
 
+stree_stat_t *parse_stat(parse_t *parse);
 stree_ident_t *parse_ident(parse_t *parse);
 
Index: uspace/app/sbi/src/rdata.c
===================================================================
--- uspace/app/sbi/src/rdata.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/rdata.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -42,4 +42,6 @@
 static void rdata_array_copy(rdata_array_t *src, rdata_array_t **dest);
 static void rdata_object_copy(rdata_object_t *src, rdata_object_t **dest);
+static void rdata_resource_copy(rdata_resource_t *src,
+    rdata_resource_t **dest);
 
 static int rdata_array_get_dim(rdata_array_t *array);
@@ -241,4 +243,17 @@
 
 	return string_v;
+}
+
+rdata_resource_t *rdata_resource_new(void)
+{
+	rdata_resource_t *resource_v;
+
+	resource_v = calloc(1, sizeof(rdata_resource_t));
+	if (resource_v == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return resource_v;
 }
 
@@ -306,4 +321,7 @@
 		rdata_object_copy(src->u.object_v, &nvar->u.object_v);
 		break;
+	case vc_resource:
+		rdata_resource_copy(src->u.resource_v, &nvar->u.resource_v);
+		break;
 	}
 
@@ -348,4 +366,10 @@
 	printf("Unimplemented: Copy object.\n");
 	exit(1);
+}
+
+static void rdata_resource_copy(rdata_resource_t *src, rdata_resource_t **dest)
+{
+	*dest = rdata_resource_new();
+	(*dest)->data = src->data;
 }
 
@@ -389,4 +413,5 @@
 	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;
 	}
 
Index: uspace/app/sbi/src/rdata.h
===================================================================
--- uspace/app/sbi/src/rdata.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/rdata.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -47,4 +47,5 @@
 rdata_int_t *rdata_int_new(void);
 rdata_string_t *rdata_string_new(void);
+rdata_resource_t *rdata_resource_new(void);
 
 void rdata_array_alloc_element(rdata_array_t *array);
Index: uspace/app/sbi/src/rdata_t.h
===================================================================
--- uspace/app/sbi/src/rdata_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/rdata_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -44,4 +44,5 @@
 } rdata_int_t;
 
+
 /** String variable */
 typedef struct {
@@ -92,4 +93,14 @@
 } rdata_object_t;
 
+/** Resource handle
+ *
+ * Binding to external data. This type can be used to refer to data used
+ * by builtin functions (such as files).
+ */
+typedef struct {
+	/** Only understood by the right builtin function. */
+	void *data;
+} rdata_resource_t;
+
 typedef enum var_class {
 	/** Integer */
@@ -109,5 +120,8 @@
 
 	/** Object */
-	vc_object
+	vc_object,
+
+	/** Interpreter builtin resource */
+	vc_resource
 } var_class_t;
 
@@ -128,4 +142,5 @@
 		rdata_array_t *array_v;
 		rdata_object_t *object_v;
+		rdata_resource_t *resource_v;
 	} u;
 } rdata_var_t;
Index: uspace/app/sbi/src/run.c
===================================================================
--- uspace/app/sbi/src/run.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/run.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -48,5 +48,4 @@
 
 static void run_block(run_t *run, stree_block_t *block);
-static void run_stat(run_t *run, stree_stat_t *stat);
 static void run_exps(run_t *run, stree_exps_t *exps);
 static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
@@ -132,5 +131,5 @@
 #ifdef DEBUG_RUN_TRACE
 	printf("Start executing function '");
-	symbol_print_fqn(proc_sym);
+	symbol_print_fqn(proc->outer_symbol);
 	printf("'.\n");
 #endif
@@ -159,5 +158,5 @@
 #ifdef DEBUG_RUN_TRACE
 	printf("Done executing procedure '");
-	symbol_print_fqn(proc);
+	symbol_print_fqn(proc->outer_symbol);
 	printf("'.\n");
 
@@ -216,5 +215,5 @@
 
 /** Run statement. */
-static void run_stat(run_t *run, stree_stat_t *stat)
+void run_stat(run_t *run, stree_stat_t *stat)
 {
 #ifdef DEBUG_RUN_TRACE
Index: uspace/app/sbi/src/run.h
===================================================================
--- uspace/app/sbi/src/run.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/run.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -35,4 +35,5 @@
 void run_program(run_t *run, stree_program_t *prog);
 void run_proc(run_t *run, run_proc_ar_t *proc_ar, rdata_item_t **res);
+void run_stat(run_t *run, stree_stat_t *stat);
 
 void run_print_fun_bt(run_t *run);
Index: uspace/app/sbi/src/run_expr.c
===================================================================
--- uspace/app/sbi/src/run_expr.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/run_expr.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -96,4 +96,5 @@
     rdata_item_t *base, list_t *args, rdata_item_t **res);
 static void run_assign(run_t *run, stree_assign_t *assign, rdata_item_t **res);
+static void run_as(run_t *run, stree_as_t *as_op, rdata_item_t **res);
 
 /** Evaluate expression. */
@@ -134,4 +135,7 @@
 	case ec_assign:
 		run_assign(run, expr->u.assign, res);
+		break;
+	case ec_as:
+		run_as(run, expr->u.as_op, res);
 		break;
 	}
@@ -1360,5 +1364,4 @@
 }
 
-
 /** Execute assignment. */
 static void run_assign(run_t *run, stree_assign_t *assign, rdata_item_t **res)
@@ -1387,4 +1390,67 @@
 
 	*res = NULL;
+}
+
+/** Execute @c as conversion. */
+static void run_as(run_t *run, stree_as_t *as_op, rdata_item_t **res)
+{
+	rdata_item_t *rarg_i;
+	rdata_item_t *rarg_vi;
+	rdata_item_t *rarg_di;
+	rdata_var_t *arg_vref;
+	tdata_item_t *dtype;
+	run_proc_ar_t *proc_ar;
+
+	stree_symbol_t *obj_csi_sym;
+	stree_csi_t *obj_csi;
+
+#ifdef DEBUG_RUN_TRACE
+	printf("Run @c as conversion operation.\n");
+#endif
+	run_expr(run, as_op->arg, &rarg_i);
+
+	/*
+	 * This should always be a reference if the argument is indeed
+	 * a class instance.
+	 */
+	assert(run_item_get_vc(run, rarg_i) == vc_ref);
+	run_cvt_value_item(run, rarg_i, &rarg_vi);
+	assert(rarg_vi->ic == ic_value);
+
+	if (rarg_vi->u.value->var->u.ref_v->vref == NULL) {
+		/* Nil reference is always okay. */
+		*res = rarg_vi;
+		return;
+	}
+
+	run_dereference(run, rarg_vi, &rarg_di);
+
+	/* Now we should have a variable address. */
+	assert(rarg_di->ic == ic_address);
+	assert(rarg_di->u.address->ac == ac_var);
+
+	arg_vref = rarg_di->u.address->u.var_a->vref;
+
+	proc_ar = run_get_current_proc_ar(run);
+	/* XXX Memoize to avoid recomputing. */
+	run_texpr(run->program, proc_ar->proc->outer_symbol->outer_csi,
+	    as_op->dtype, &dtype);
+
+	assert(arg_vref->vc == vc_object);
+	obj_csi_sym = arg_vref->u.object_v->class_sym;
+	obj_csi = symbol_to_csi(obj_csi_sym);
+	assert(obj_csi != NULL);
+
+	if (tdata_is_csi_derived_from_ti(obj_csi, dtype) != b_true) {
+		printf("Error: Run-time type conversion error. Object is "
+		    "of type '");
+		symbol_print_fqn(obj_csi_sym);
+		printf("' which is not derived from '");
+		tdata_item_print(dtype);
+		printf("'.\n");
+		exit(1);
+	}
+
+	*res = rarg_vi;
 }
 
Index: uspace/app/sbi/src/run_t.h
===================================================================
--- uspace/app/sbi/src/run_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/run_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -30,4 +30,5 @@
 #define RUN_T_H_
 
+#include "intmap_t.h"
 #include "list_t.h"
 
Index: uspace/app/sbi/src/run_texpr.c
===================================================================
--- uspace/app/sbi/src/run_texpr.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/run_texpr.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -165,4 +165,5 @@
 	case tlc_int: tpc = tpc_int; break;
 	case tlc_string: tpc = tpc_string; break;
+	case tlc_resource: tpc = tpc_resource; break;
 	}
 
Index: uspace/app/sbi/src/stree.c
===================================================================
--- uspace/app/sbi/src/stree.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stree.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -136,4 +136,18 @@
 }
 
+stree_symbol_attr_t *stree_symbol_attr_new(symbol_attr_class_t sac)
+{
+	stree_symbol_attr_t *symbol_attr;
+
+	symbol_attr = calloc(1, sizeof(stree_symbol_attr_t));
+	if (symbol_attr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	symbol_attr->sac = sac;
+	return symbol_attr;
+}
+
 stree_proc_t *stree_proc_new(void)
 {
@@ -414,4 +428,17 @@
 }
 
+stree_as_t *stree_as_new(void)
+{
+	stree_as_t *as_expr;
+
+	as_expr = calloc(1, sizeof(stree_as_t));
+	if (as_expr == NULL) {
+		printf("Memory allocation failed.\n");
+		exit(1);
+	}
+
+	return as_expr;
+}
+
 stree_nameref_t *stree_nameref_new(void)
 {
@@ -572,4 +599,22 @@
 
 	return program;
+}
+
+/** Determine if @a symbol has attribute of class @a sac. */
+bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac)
+{
+	list_node_t *node;
+	stree_symbol_attr_t *attr;
+
+	node = list_first(&symbol->attr);
+	while (node != NULL) {
+		attr = list_node_data(node, stree_symbol_attr_t *);
+		if (attr->sac == sac)
+			return b_true;
+
+		node = list_next(&symbol->attr, node);
+	}
+
+	return b_false;
 }
 
Index: uspace/app/sbi/src/stree.h
===================================================================
--- uspace/app/sbi/src/stree.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stree.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -40,4 +40,6 @@
 stree_prop_t *stree_prop_new(void);
 
+stree_symbol_attr_t *stree_symbol_attr_new(symbol_attr_class_t sac);
+
 stree_proc_t *stree_proc_new(void);
 stree_proc_arg_t *stree_proc_arg_new(void);
@@ -64,4 +66,5 @@
 stree_call_t *stree_call_new(void);
 stree_index_t *stree_index_new(void);
+stree_as_t *stree_as_new(void);
 stree_nameref_t *stree_nameref_new(void);
 
@@ -80,4 +83,5 @@
 stree_program_t *stree_program_new(void);
 
+bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac);
 bool_t stree_arg_has_attr(stree_proc_arg_t *arg, arg_attr_class_t aac);
 bool_t stree_is_csi_derived_from_csi(stree_csi_t *a, stree_csi_t *b);
Index: uspace/app/sbi/src/stree_t.h
===================================================================
--- uspace/app/sbi/src/stree_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stree_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -31,4 +31,5 @@
 
 #include "list_t.h"
+#include "builtin_t.h"
 
 /*
@@ -156,4 +157,12 @@
 	list_t args; /* of stree_expr_t */
 } stree_index_t;
+
+/** @c as conversion operation */
+typedef struct {
+	/** Expression to convert */
+	struct stree_expr *arg;
+	/** Destination type of conversion. */
+	struct stree_texpr *dtype;
+} stree_as_t;
 
 /** Arithmetic expression class */
@@ -168,5 +177,6 @@
 	ec_call,
 	ec_assign,
-	ec_index
+	ec_index,
+	ec_as
 } expr_class_t;
 
@@ -188,4 +198,5 @@
 		stree_index_t *index;
 		stree_assign_t *assign;
+		stree_as_t *as_op;
 	} u;
 } stree_expr_t;
@@ -200,4 +211,5 @@
 typedef enum {
 	tlc_int,
+	tlc_resource,
 	tlc_string
 } tliteral_class_t;
@@ -388,6 +400,9 @@
 	struct stree_symbol *outer_symbol;
 
-	/** Main block */
+	/** Main block for regular procedures */
 	stree_block_t *body;
+
+	/** Builtin handler for builtin procedures */
+	builtin_proc_t bi_handler;
 } stree_proc_t;
 
@@ -512,4 +527,16 @@
 } stree_module_t;
 
+/** Symbol attribute class */
+typedef enum {
+	/** Builtin symbol (interpreter hook) */
+	sac_builtin
+} symbol_attr_class_t;
+
+/** Symbol atribute */
+typedef struct {
+	symbol_attr_class_t sac;
+} stree_symbol_attr_t;
+
+
 typedef enum {
 	sc_csi,
@@ -539,4 +566,7 @@
 	/** Containing block (for block-level symbols) */
 	stree_block_t *outer_block;
+
+	/** Symbol attributes. */
+	list_t attr; /* of stree_symbol_attr_t */
 } stree_symbol_t;
 
@@ -545,4 +575,7 @@
 	/** The one and only module in the program */
 	stree_module_t *module;
+
+	/** Builtin symbols binding. */
+	struct builtin *builtin;
 } stree_program_t;
 
Index: uspace/app/sbi/src/stype.c
===================================================================
--- uspace/app/sbi/src/stype.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stype.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -54,5 +54,4 @@
 
 static void stype_block(stype_t *stype, stree_block_t *block);
-static void stype_stat(stype_t *stype, stree_stat_t *stat);
 
 static void stype_vdecl(stype_t *stype, stree_vdecl_t *vdecl_s);
@@ -253,5 +252,5 @@
 
 /** Type statement */
-static void stype_stat(stype_t *stype, stree_stat_t *stat)
+void stype_stat(stype_t *stype, stree_stat_t *stat)
 {
 #ifdef DEBUG_TYPE_TRACE
Index: uspace/app/sbi/src/stype.h
===================================================================
--- uspace/app/sbi/src/stype.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stype.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -33,4 +33,5 @@
 
 void stype_module(stype_t *stype, stree_module_t *module);
+void stype_stat(stype_t *stype, stree_stat_t *stat);
 
 stree_expr_t *stype_convert(stype_t *stype, stree_expr_t *expr,
Index: uspace/app/sbi/src/stype_expr.c
===================================================================
--- uspace/app/sbi/src/stype_expr.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/stype_expr.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -90,4 +90,5 @@
 static void stype_assign(stype_t *stype, stree_assign_t *assign,
     tdata_item_t **rtitem);
+static void stype_as(stype_t *stype, stree_as_t *as_op, tdata_item_t **rtitem);
 
 
@@ -96,7 +97,11 @@
 {
 	tdata_item_t *et;
+
 #ifdef DEBUG_TYPE_TRACE
 	printf("Type expression.\n");
 #endif
+	/* Silence warning. */
+	et = NULL;
+
 	switch (expr->ec) {
 	case ec_nameref: stype_nameref(stype, expr->u.nameref, &et); break;
@@ -110,4 +115,5 @@
 	case ec_index: stype_index(stype, expr->u.index, &et); break;
 	case ec_assign: stype_assign(stype, expr->u.assign, &et); break;
+	case ec_as: stype_as(stype, expr->u.as_op, &et); break;
 	}
 
@@ -337,4 +343,7 @@
 		rtpc = tpc_string;
 		break;
+	case tpc_resource:
+		printf("Error: Cannot apply operator to resource type.\n");
+		exit(1);
 	}
 
@@ -829,2 +838,26 @@
 	*rtitem = NULL;
 }
+
+/** Type @c as conversion. */
+static void stype_as(stype_t *stype, stree_as_t *as_op, tdata_item_t **rtitem)
+{
+	tdata_item_t *titem;
+
+#ifdef DEBUG_TYPE_TRACE
+	printf("Evaluate type of @c as conversion.\n");
+#endif
+	stype_expr(stype, as_op->arg);
+	run_texpr(stype->program, stype->current_csi, as_op->dtype, &titem);
+
+	/* Check that target type is derived from argument type. */
+	if (tdata_is_ti_derived_from_ti(titem, as_op->arg->titem) != b_true) {
+		printf("Error: Target of 'as' operator '");
+		tdata_item_print(titem);
+		printf("' is not derived from '");
+		tdata_item_print(as_op->arg->titem);
+		printf("'.\n");
+		exit(1);
+	}
+
+	*rtitem = titem;
+}
Index: uspace/app/sbi/src/symbol.c
===================================================================
--- uspace/app/sbi/src/symbol.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/symbol.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -329,5 +329,5 @@
 	if (symbol->outer_csi != NULL) {
 		outer_sym = csi_to_symbol(symbol->outer_csi);
-		symbol_print_fqn( outer_sym);
+		symbol_print_fqn(outer_sym);
 		printf(".");
 	}
Index: uspace/app/sbi/src/tdata.c
===================================================================
--- uspace/app/sbi/src/tdata.c	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/tdata.c	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -60,4 +60,24 @@
 }
 
+/**
+ * Determine if CSI described by type item @a a is derived from CSI described
+ * by type item @a tb.
+ */
+bool_t tdata_is_ti_derived_from_ti(tdata_item_t *ta, tdata_item_t *tb)
+{
+	bool_t res;
+
+	switch (ta->tic) {
+	case tic_tobject:
+		res = tdata_is_csi_derived_from_ti(ta->u.tobject->csi, tb);
+		break;
+	default:
+		printf("Error: Derived type is not a CSI.\n");
+		exit(1);
+	}
+
+	return res;
+}
+
 /** Determine if two type items are equal (i.e. describe the same type). */
 bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b)
@@ -137,4 +157,5 @@
 	case tpc_nil: printf("nil"); break;
 	case tpc_string: printf("string"); break;
+	case tpc_resource: printf("resource"); break;
 	}
 }
Index: uspace/app/sbi/src/tdata.h
===================================================================
--- uspace/app/sbi/src/tdata.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/tdata.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -39,4 +39,5 @@
 
 bool_t tdata_is_csi_derived_from_ti(stree_csi_t *a, tdata_item_t *tb);
+bool_t tdata_is_ti_derived_from_ti(tdata_item_t *ta, tdata_item_t *tb);
 bool_t tdata_item_equal(tdata_item_t *a, tdata_item_t *b);
 void tdata_item_print(tdata_item_t *titem);
Index: uspace/app/sbi/src/tdata_t.h
===================================================================
--- uspace/app/sbi/src/tdata_t.h	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/app/sbi/src/tdata_t.h	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -39,5 +39,7 @@
 	tpc_nil,
 	/** String type */
-	tpc_string
+	tpc_string,
+	/** Resource type */
+	tpc_resource
 } tprimitive_class_t;
 
Index: uspace/dist/sysel/except.sy
===================================================================
--- uspace/dist/sysel/except.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/except.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -28,5 +28,5 @@
 
 class ExceptionDemo is
-	fun foo() : int is
+	fun foo() is
 	        Builtin.WriteLine("Entered foo().");
 		raise new BaseException();
Index: uspace/dist/sysel/hexec.sy
===================================================================
--- uspace/dist/sysel/hexec.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/hexec.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -29,6 +29,6 @@
 class HelenOSExecDemo is
 	fun Main() is
-		Builtin.Exec("/app/tester");
-		Builtin.Exec("/app/tester", "print1");
+		Task.Exec("/app/tester");
+		Task.Exec("/app/tester", "print1");
 	end
 end
Index: uspace/dist/sysel/inherit.sy
===================================================================
--- uspace/dist/sysel/inherit.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/inherit.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -45,8 +45,11 @@
 	fun Main() is
 		var a : A;
+		var c : C;
 
+		-- Construct and assign object.
 		a = new A();
 		a.Foo();
 
+		-- Implicit conversion to base type.
 		a = new B();
 		a.Foo();
@@ -54,4 +57,13 @@
 		a = new C();
 		a.Foo();
+
+		-- Test 'as' operator for conversion to derived type.
+		c = a as C;
+
+		-- Test grandfather class.
+		var d : Object;
+		d = a;
+		d = new B();
+		d = c;
 	end
 end
Index: uspace/dist/sysel/list.sy
===================================================================
--- uspace/dist/sysel/list.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/list.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -27,7 +27,9 @@
 --
 
+-- Doubly-linked list implementation.
 class List is
 	var head : ListNode;
 
+	-- Initialize list.
 	fun Init() is
 		head = new ListNode();
@@ -36,4 +38,5 @@
 	end
 
+	-- Append new entry at the end of the list.
 	fun Append(data : int) is
 		var n : ListNode;
@@ -53,6 +56,18 @@
 	end
 
-	fun GetFirst() : ListNode is
-		return head.next;
+	-- Return first node in the list or @c nil if there is none.
+	prop First : ListNode is
+		get is
+		    return get_first();
+		end
+	end
+
+	-- Return first node in the list or @c nil if there is none.
+	fun get_first() : ListNode is
+		if head.next == head then
+			return nil;
+		else
+			return head.next;
+		end
 	end
 end
@@ -65,5 +80,27 @@
 	var head : ListNode;
 
-	fun GetNext() : ListNode is
+	-- Value stored in this node.
+	prop Value : int is
+		get is
+			return value;
+		end
+	end
+
+	-- Previous node in list.
+	prop Prev : ListNode is
+		get is
+			return get_prev();
+		end
+	end
+
+	-- Next node in list.
+	prop Next : ListNode is
+		get is
+			return get_next();
+		end
+	end
+
+	-- Get next node.
+	fun get_next() : ListNode is
 		if next != head then
 			return next;
@@ -73,5 +110,6 @@
 	end
 
-	fun GetPrev() : ListNode is
+	-- Get previous node.
+	fun get_prev() : ListNode is
 		if prev != head then
 			return next;
@@ -81,7 +119,4 @@
 	end
 
-	fun GetValue() : int is
-		return value;
-	end
 end
 
@@ -100,8 +135,8 @@
 		var n : ListNode;
 
-		n = list.GetFirst();
+		n = list.First;
 		while n != nil do
 			Builtin.WriteLine(n.value);
-			n = n.GetNext();
+			n = n.Next;
 		end
 	end
Index: uspace/dist/sysel/property.sy
===================================================================
--- uspace/dist/sysel/property.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/property.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -27,5 +27,5 @@
 --
 
-class A is
+class Foo is
 	var x : int;
 
@@ -68,12 +68,39 @@
 		end
 	end
+
+	--
+	-- Class-type property. This is used for demonstrating property
+	-- field access. This case is still quite easy. It does not require
+	-- read-modify-write. Since class is a reference type, access
+	-- operator will read the value and dereference it, thereby
+	-- getting somewhere else (so the value will not be modified and
+	-- need not be written back).
+	--
+
+	var bprop : Bar;
+
+	prop B : Bar is
+		get is
+			Builtin.WriteLine("Getting B");
+			return bprop;
+		end
+		set value is
+			Builtin.WriteLine("Setting B");
+			bprop = value;
+		end
+	end
+
+end
+
+class Bar is
+	var i : int;
 end
 
 class PropertyDemo is
 	fun Main() is
-		var a : A;
+		var a : Foo;
 		var i : int;
 
-		a = new A();
+		a = new Foo();
 
 		-- Get value of named property.
@@ -96,4 +123,16 @@
 		Builtin.WriteLine("Main(): Got ");
 		Builtin.WriteLine(i);
+
+		-- Property field access
+		var b : Bar;
+
+		b = new Bar();
+
+		b.i = 42;
+		a.bprop = b;
+
+		Builtin.WriteLine(a.bprop.i);
+		a.bprop.i = 2;
+		Builtin.WriteLine(a.bprop.i);
 	end
 end
Index: uspace/dist/sysel/string.sy
===================================================================
--- uspace/dist/sysel/string.sy	(revision b535aebfcb7a8ea104bc8714a16879753bb853d0)
+++ uspace/dist/sysel/string.sy	(revision 37f527bc07305262cbe6d63e6c152419e5050304)
@@ -31,4 +31,12 @@
 		-- Concatenate some strings.
 		Builtin.WriteLine("One-" + "two-" + "three!");
+
+		-- Extract characters from a string.
+		var i : int;
+		i = 0;
+		while i < 5 do
+			Builtin.WriteLine("ABCDE"[i]);
+			i = i + 1;
+		end
 	end
 end
